0.8.0-alt1 0.8.0-alt1
authorKachalov Anton <mouse@altlinux.ru>
Wed, 21 Dec 2005 13:24:37 +0000 (13:24 +0000)
committerKirill A. Shutemov <k.shutemov@gmail.com>
Wed, 21 Dec 2005 13:24:37 +0000 (13:24 +0000)
- 0.8.0

161 files changed:
.gear-rules
qemu-0.7.0-alt-kqemu.patch [deleted file]
qemu-0.7.1-alt-guiargs.patch [deleted file]
qemu-0.7.2-gtk.patch [deleted file]
qemu-0.8.0-alt-kqemu.patch [new file with mode: 0644]
qemu-gtk/callbacks.c [deleted file]
qemu-gtk/callbacks.h [deleted file]
qemu-gtk/fullscreen.h [deleted file]
qemu-gtk/gdk_keysym.h [deleted file]
qemu-gtk/gdk_set_window_pointer.c [deleted file]
qemu-gtk/gtk2.c [deleted file]
qemu-gtk/gtk2gui.c [deleted file]
qemu-gtk/interface.c [deleted file]
qemu-gtk/interface.h [deleted file]
qemu-gtk/null_fs.c [deleted file]
qemu-gtk/support.c [deleted file]
qemu-gtk/support.h [deleted file]
qemu-gtk/xvid_fs.c [deleted file]
qemu.spec
qemu/.cvsignore
qemu/Changelog
qemu/Makefile
qemu/Makefile.target
qemu/TODO
qemu/VERSION
qemu/alpha-dis.c
qemu/audio/alsaaudio.c [new file with mode: 0644]
qemu/audio/audio.c
qemu/audio/audio.h
qemu/audio/audio_int.h
qemu/audio/audio_template.h [new file with mode: 0644]
qemu/audio/coreaudio.c [new file with mode: 0644]
qemu/audio/dsound_template.h [new file with mode: 0644]
qemu/audio/dsoundaudio.c [new file with mode: 0644]
qemu/audio/fmodaudio.c
qemu/audio/mixeng.c
qemu/audio/mixeng.h
qemu/audio/mixeng_template.h
qemu/audio/noaudio.c
qemu/audio/ossaudio.c
qemu/audio/rate_template.h [new file with mode: 0644]
qemu/audio/sdlaudio.c
qemu/audio/sys-queue.h [new file with mode: 0644]
qemu/audio/wavaudio.c
qemu/block-qcow.c
qemu/block-vmdk.c
qemu/block-vvfat.c
qemu/block.c
qemu/block_int.h
qemu/cocoa.m
qemu/configure
qemu/cpu-all.h
qemu/cpu-defs.h
qemu/cpu-exec.c
qemu/dis-asm.h
qemu/disas.c
qemu/disas.h
qemu/exec-all.h
qemu/exec.c
qemu/gdbstub.c
qemu/hw/adlib.c
qemu/hw/apic.c
qemu/hw/dma.c
qemu/hw/es1370.c [new file with mode: 0644]
qemu/hw/esp.c
qemu/hw/heathrow_pic.c
qemu/hw/integratorcp.c [new file with mode: 0644]
qemu/hw/iommu.c
qemu/hw/lance.c
qemu/hw/m48t08.c [deleted file]
qemu/hw/m48t08.h [deleted file]
qemu/hw/m48t59.c
qemu/hw/m48t59.h
qemu/hw/mips_r4k.c
qemu/hw/ne2000.c
qemu/hw/openpic.c
qemu/hw/parallel.c
qemu/hw/pc.c
qemu/hw/pci.c
qemu/hw/pckbd.c
qemu/hw/ppc.c
qemu/hw/ppc_chrp.c
qemu/hw/ppc_prep.c
qemu/hw/ps2.c [new file with mode: 0644]
qemu/hw/sb16.c
qemu/hw/serial.c
qemu/hw/slavio_intctl.c
qemu/hw/slavio_misc.c
qemu/hw/slavio_serial.c
qemu/hw/slavio_timer.c
qemu/hw/smc91c111.c [new file with mode: 0644]
qemu/hw/sun4m.c
qemu/hw/sun4u.c
qemu/hw/usb-hid.c [new file with mode: 0644]
qemu/hw/usb-uhci.c [new file with mode: 0644]
qemu/hw/usb.c [new file with mode: 0644]
qemu/hw/usb.h [new file with mode: 0644]
qemu/linux-user/elfload.c
qemu/linux-user/main.c
qemu/linux-user/mips/syscall.h [new file with mode: 0644]
qemu/linux-user/mips/syscall_nr.h [new file with mode: 0644]
qemu/linux-user/mips/termbits.h [new file with mode: 0644]
qemu/linux-user/signal.c
qemu/linux-user/syscall.c
qemu/linux-user/syscall_defs.h
qemu/m68k-dis.c [new file with mode: 0644]
qemu/mips-dis.c
qemu/monitor.c
qemu/pc-bios/proll.elf
qemu/pc-bios/proll.patch
qemu/qemu-binfmt-conf.sh
qemu/qemu-doc.html
qemu/qemu-doc.texi
qemu/qemu-img.1
qemu/qemu-tech.html
qemu/qemu.1
qemu/sdl.c
qemu/softmmu_exec.h [new file with mode: 0644]
qemu/softmmu_header.h
qemu/softmmu_template.h
qemu/sparc-dis.c
qemu/target-arm/cpu.h
qemu/target-arm/exec.h
qemu/target-arm/helper.c [new file with mode: 0644]
qemu/target-arm/op.c
qemu/target-arm/op_helper.c
qemu/target-arm/op_mem.h [new file with mode: 0644]
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/op.c
qemu/target-i386/ops_mem.h
qemu/target-i386/translate.c
qemu/target-mips/cpu.h
qemu/target-mips/exec.h
qemu/target-mips/helper.c
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/translate.c
qemu/target-ppc/cpu.h
qemu/target-ppc/exec.h
qemu/target-ppc/helper.c
qemu/target-ppc/op.c
qemu/target-ppc/translate.c
qemu/target-ppc/translate_init.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/tests/qruncom.c
qemu/translate-all.c
qemu/usb-linux.c [new file with mode: 0644]
qemu/vl.c
qemu/vl.h

index 78e9dd3..2aed898 100644 (file)
@@ -1,5 +1,4 @@
 copy: *.patch
-tar.gz: kqemu base=kqemu
+tar.gz: kqemu name=kqemu-0.7.2 base=kqemu
 copy: kqemu-permission
 tar.bz2: qemu
-tar.bz2: qemu-gtk name=qemu-gtk-20050716 base=
diff --git a/qemu-0.7.0-alt-kqemu.patch b/qemu-0.7.0-alt-kqemu.patch
deleted file mode 100644 (file)
index d088ab6..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
---- Makefile.orig      2005-04-28 00:52:05 +0400
-+++ Makefile   2005-05-19 21:29:57 +0400
-@@ -17,13 +17,6 @@
-       for d in $(TARGET_DIRS); do \
-       $(MAKE) -C $$d $@ || exit 1 ; \
-         done
--ifdef CONFIG_KQEMU
--ifdef CONFIG_WIN32
--      $(MAKE) -C kqemu -f Makefile.winnt
--else
--      $(MAKE) -C kqemu
--endif
--endif
- qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c
-       $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
-@@ -39,9 +32,6 @@
-       for d in $(TARGET_DIRS); do \
-       $(MAKE) -C $$d $@ || exit 1 ; \
-         done
--ifdef CONFIG_KQEMU
--      $(MAKE) -C kqemu clean
--endif
- distclean: clean
-       rm -f config-host.mak config-host.h
-@@ -73,9 +63,6 @@
-       for d in $(TARGET_DIRS); do \
-       $(MAKE) -C $$d $@ || exit 1 ; \
-         done
--ifdef CONFIG_KQEMU
--      cd kqemu ; ./install.sh
--endif
- # various test targets
- test speed test2: all
---- configure.orig     2005-04-28 00:52:05 +0400
-+++ configure  2005-05-19 21:48:11 +0400
-@@ -364,41 +364,12 @@
-         kqemu="no"
-     fi
- fi
--  
--# Linux specific kqemu configuration
--if test $kqemu = "yes" -a $linux = "yes" ; then
--# find the kernel path
--if test -z "$kernel_path" ; then
--kernel_version=`uname -r`
--kernel_path="/lib/modules/$kernel_version/build"
--if test '!' -d "$kernel_path/include" ; then 
--    kernel_path="/usr/src/linux"
--    if test '!' -d "$kernel_path/include" ; then 
--        echo "Could not find kernel includes in /lib/modules or /usr/src/linux - cannot build the kqemu module"
--        kqemu="no"
--    fi
--fi
--fi
- if test $kqemu = "yes" ; then
--
--# test that the kernel config is present
--if test '!' -f "$kernel_path/Makefile" ; then
--    echo "No Makefile file present in $kernel_path - kqemu cannot be built"
--    kqemu="no"
--fi    
--
--# find build system (2.6 or legacy)
--kbuild26="yes"
--if grep -q "PATCHLEVEL = 4" $kernel_path/Makefile ; then
--kbuild26="no"
--fi
--
-+    # find build system (2.6 or legacy)
-+    kbuild26="yes"
- fi # kqemu
--fi # kqemu and linux
--
--
- echo "Install prefix    $prefix"
- echo "BIOS directory    $datadir"
- echo "binary directory  $bindir"
diff --git a/qemu-0.7.1-alt-guiargs.patch b/qemu-0.7.1-alt-guiargs.patch
deleted file mode 100644 (file)
index 89b6189..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
---- qemu-gtk/vl.c.orig 2005-08-04 14:33:41 +0400
-+++ qemu-gtk/vl.c      2005-08-04 14:36:06 +0400
-@@ -3179,6 +3179,8 @@
-     macaddr[4] = 0x34;
-     macaddr[5] = 0x56;
-     
-+    gui_checkargs(&argc, &argv);
-+
-     optind = 1;
-     for(;;) {
-         if (optind >= argc)
-@@ -3546,7 +3548,6 @@
-             boot_device = 'd';
-     }
--    gui_checkargs(&argc, &argv);
- #if !defined(CONFIG_SOFTMMU)
-     /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
-     {
diff --git a/qemu-0.7.2-gtk.patch b/qemu-0.7.2-gtk.patch
deleted file mode 100644 (file)
index 8c2de78..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-diff -Naur qemu-0.7.2/configure qemu-0.7.2-gtk/configure
---- qemu-0.7.2/configure       2005-09-20 11:35:05 +0400
-+++ qemu-0.7.2-gtk/configure   2005-09-20 11:34:49 +0400
-@@ -15,6 +15,7 @@
- TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
- TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}"
- TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
-+TMPF="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}-conf"
- # default parameters
- prefix=""
-@@ -171,6 +172,10 @@
-   ;;
-   --disable-sdl) sdl="no"
-   ;;
-+  --enable-gtk) gtk="yes"
-+  ;;
-+  --set-fs-driver=*) fsdrv=`echo $opt | cut -d '=' -f 2`
-+  ;;
-   --enable-fmod) fmod="yes"
-   ;;
-   --fmod-lib=*) fmod_lib=${opt#--fmod-lib=}
-@@ -319,6 +324,64 @@
- fi # cross compilation
- fi # -z $sdl
-+##########################################
-+# GTK probe
-+
-+gtk_too_old=no
-+
-+if test -z "$gtk" ; then
-+
-+gtk=no
-+
-+# normal GTK probe
-+cat > $TMPC << EOF
-+#include <stdlib.h>
-+#include <gtk/gtk.h>
-+int main(int argc, char **argv) { gtk_init(&argc, &argv); return EXIT_SUCCESS; }
-+EOF
-+
-+if $cc -o $TMPE `pkg-config --cflags --libs gtk+-2.0 2> /dev/null` $TMPC 2> /dev/null ; then
-+_gtkversion=`pkg-config --modversion gtk+-2.0 | sed 's/[^0-9]//g'`
-+if test "$_sdlversion" -lt 240 ; then
-+  gtk_too_old=yes
-+else
-+  gtk=yes
-+
-+fi
-+
-+fi # gtk compile test
-+
-+fi # -z $gtk
-+
-+if [ "$gtk" = "yes" ]; then
-+
-+if [ "$fsdrv" = "" ] ; then
-+
-+if [ "$bsd" = "yes" -o "$linux" = "yes" ]; then
-+  fsdrv=xvid_fs.c
-+else
-+  fsdrv=null_fs.c
-+fi
-+
-+fi # fsdrv test
-+
-+if [ "$fsdrv" = "xvid_fs.c" -o "$fsdrv" = "null_fs.c" ]; then
-+  echo "fsdrv=$fsdrv" >> $TMPF
-+else
-+  echo "Warning: unknown gtk fullscreen driver: $fsdrv - using null driver"
-+  echo 'fsdrv=null_fs.c' >> $TMPF
-+  fsdrv=null_fs.c
-+fi
-+
-+if [ "$fsdrv" = "xvid_fs.c" ]; then
-+  FS_LIBS="-lX11 -lXxf86vm -lXext"
-+  [ "$cpu" = "x86_64" ] && lib=lib64
-+  FS_LIBS="$FS_LIBS -L/usr/X11R6/${lib:-lib}"
-+  echo FS_LIBS=\"$FS_LIBS\" >> $TMPF
-+fi
-+
-+fi # gtk=yes test
-+
- if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
- cat << EOF
-@@ -408,6 +471,8 @@
- if test "$sdl" != "no" ; then
-     echo "SDL static link   $sdl_static"
- fi
-+echo "GTK support       $gtk"
-+echo "GTK FS driver     $fsdrv"
- echo "mingw32 support   $mingw32"
- echo "Adlib support     $adlib"
- echo -n "FMOD support      $fmod"
-@@ -624,6 +689,8 @@
- interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"`
- echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h
-+. $TMPF
-+
- if test "$target_cpu" = "i386" ; then
-   echo "TARGET_ARCH=i386" >> $config_mak
-   echo "#define TARGET_ARCH \"i386\"" >> $config_h
-@@ -710,6 +777,17 @@
-     fi
- fi
-+if test "$gtk" = "yes" ; then
-+    . $TMPF
-+    echo "#define CONFIG_GTK 1" >> $config_h
-+    echo "CONFIG_GTK=yes" >> $config_mak
-+    echo "GTK_LIBS=`pkg-config --libs gtk+-2.0`" >> $config_mak
-+    echo "GTK_CFLAGS=`pkg-config --cflags gtk+-2.0`" >> $config_mak
-+    echo "FSDRV=$fsdrv" >> $config_mak
-+    echo "FS_LIBS=$FS_LIBS" >> $config_mak
-+    echo "" >> $config_mak
-+fi
-+
- if test "$cocoa" = "yes" ; then
-     echo "#define CONFIG_COCOA 1" >> $config_h
-     echo "CONFIG_COCOA=yes" >> $config_mak
-@@ -729,4 +807,4 @@
-     done
- fi
--rm -f $TMPO $TMPC $TMPE $TMPS
-+rm -f $TMPO $TMPC $TMPE $TMPS $TMPF
-diff -Naur qemu-0.7.2/Makefile.target qemu-0.7.2-gtk/Makefile.target
---- qemu-0.7.2/Makefile.target 2005-09-20 11:35:05 +0400
-+++ qemu-0.7.2-gtk/Makefile.target     2005-09-20 11:34:49 +0400
-@@ -314,6 +314,13 @@
- ifdef CONFIG_SDL
- VL_OBJS+=sdl.o
- endif
-+ifdef CONFIG_GTK
-+VL_OBJS+=gtk2.o
-+VL_OBJS+=callbacks.o
-+VL_OBJS+=interface.o
-+VL_OBJS+=support.o
-+VL_OBJS+=fullscreen.o
-+endif
- ifdef CONFIG_COCOA
- VL_OBJS+=cocoa.o
- COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa
-@@ -350,7 +357,7 @@
- endif
- $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
--      $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
-+      $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(GTK_LIBS) $(FS_LIBS) $(VL_LIBS)
- cocoa.o: cocoa.m
-       $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
-@@ -358,6 +365,21 @@
- sdl.o: sdl.c keymaps.c sdl_keysym.h
-       $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
-+gtk2.o: gtk2gui.c keymaps.c gdk_keysym.h fullscreen.h interface.h callbacks.h support.h
-+      $(CC) $(CFLAGS) $(DEFINES) $(GTK_CFLAGS) -c -o $@ $<
-+
-+callbacks.o: callbacks.c callbacks.h interface.h support.h
-+      $(CC) $(CFLAGS) $(DEFINES) $(GTK_CFLAGS) -c -o $@ $<
-+
-+support.o: support.c callbacks.h interface.h support.h
-+      $(CC) $(CFLAGS) $(DEFINES) $(GTK_CFLAGS) -c -o $@ $<
-+
-+interface.o: interface.c callbacks.h interface.h support.h
-+      $(CC) $(CFLAGS) $(DEFINES) $(GTK_CFLAGS) -c -o $@ $<
-+
-+fullscreen.o: $(FSDRV) fullscreen.h
-+      $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
-+
- sdlaudio.o: sdlaudio.c
-       $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
-diff -Naur qemu-0.7.2/vl.c qemu-0.7.2-gtk/vl.c
---- qemu-0.7.2/vl.c    2005-09-04 21:11:31 +0400
-+++ qemu-0.7.2-gtk/vl.c        2005-09-20 11:34:49 +0400
-@@ -147,10 +147,13 @@
- TextConsole *vga_console;
- CharDriverState *serial_hds[MAX_SERIAL_PORTS];
- CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
-+int use_gtk = 0;
- #ifdef TARGET_I386
- int win2k_install_hack = 0;
- #endif
-+void gui_checkargs(int *, char ***);
-+
- /***********************************************************/
- /* x86 ISA bus support */
-@@ -2966,6 +2969,7 @@
-     QEMU_OPTION_cirrusvga,
-     QEMU_OPTION_g,
-     QEMU_OPTION_std_vga,
-+    QEMU_OPTION_use_gtk,
-     QEMU_OPTION_monitor,
-     QEMU_OPTION_serial,
-     QEMU_OPTION_parallel,
-@@ -3037,6 +3041,7 @@
-     { "localtime", 0, QEMU_OPTION_localtime },
-     { "isa", 0, QEMU_OPTION_isa },
-     { "std-vga", 0, QEMU_OPTION_std_vga },
-+    { "use-gtk", 0, QEMU_OPTION_use_gtk },
-     { "monitor", 1, QEMU_OPTION_monitor },
-     { "serial", 1, QEMU_OPTION_serial },
-     { "parallel", 1, QEMU_OPTION_parallel },
-@@ -3471,6 +3476,9 @@
-             case QEMU_OPTION_std_vga:
-                 cirrus_vga_enabled = 0;
-                 break;
-+            case QEMU_OPTION_use_gtk:
-+                use_gtk = 1;
-+                break;
-             case QEMU_OPTION_g:
-                 {
-                     const char *p;
-@@ -3565,6 +3573,7 @@
-             boot_device = 'd';
-     }
-+    gui_checkargs(&argc, &argv);
- #if !defined(CONFIG_SOFTMMU)
-     /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
-     {
-@@ -3727,7 +3736,17 @@
-     if (nographic) {
-         dumb_display_init(ds);
-     } else {
-+#if defined(CONFIG_GTK)
- #if defined(CONFIG_SDL)
-+      /* so we can choose */
-+      if (use_gtk)
-+        gtk2_display_init(ds, full_screen);
-+      else
-+        sdl_display_init(ds, full_screen);
-+#else
-+        gtk2_display_init(ds, full_screen);
-+#endif
-+#elif defined(CONFIG_SDL)
-         sdl_display_init(ds, full_screen);
- #elif defined(CONFIG_COCOA)
-         cocoa_display_init(ds, full_screen);
-diff -Naur qemu-0.7.2/vl.h qemu-0.7.2-gtk/vl.h
---- qemu-0.7.2/vl.h    2005-09-04 21:11:31 +0400
-+++ qemu-0.7.2-gtk/vl.h        2005-09-20 11:34:49 +0400
-@@ -612,6 +612,9 @@
- /* sdl.c */
- void sdl_display_init(DisplayState *ds, int full_screen);
-+/* gtk2.c */
-+void gtk2_display_init(DisplayState *ds, int full_screen);
-+
- /* cocoa.m */
- void cocoa_display_init(DisplayState *ds, int full_screen);
diff --git a/qemu-0.8.0-alt-kqemu.patch b/qemu-0.8.0-alt-kqemu.patch
new file mode 100644 (file)
index 0000000..d44fa00
--- /dev/null
@@ -0,0 +1,79 @@
+--- Makefile.orig      2005-04-28 00:52:05 +0400
++++ Makefile   2005-05-19 21:29:57 +0400
+@@ -17,13 +17,6 @@
+       for d in $(TARGET_DIRS); do \
+       $(MAKE) -C $$d $@ || exit 1 ; \
+         done
+-ifdef CONFIG_KQEMU
+-ifdef CONFIG_WIN32
+-      $(MAKE) -C kqemu -f Makefile.winnt
+-else
+-      $(MAKE) -C kqemu
+-endif
+-endif
+ qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c
+       $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
+@@ -39,9 +32,6 @@
+       for d in $(TARGET_DIRS); do \
+       $(MAKE) -C $$d $@ || exit 1 ; \
+         done
+-ifdef CONFIG_KQEMU
+-      $(MAKE) -C kqemu clean
+-endif
+ distclean: clean
+       rm -f config-host.mak config-host.h
+@@ -73,9 +63,6 @@
+       for d in $(TARGET_DIRS); do \
+       $(MAKE) -C $$d $@ || exit 1 ; \
+         done
+-ifdef CONFIG_KQEMU
+-      cd kqemu ; ./install.sh
+-endif
+ # various test targets
+ test speed test2: all
+--- configure.orig     2005-04-28 00:52:05 +0400
++++ configure  2005-05-19 21:48:11 +0400
+@@ -414,40 +414,13 @@
+     fi
+ fi
+-# Linux specific kqemu configuration
+-if test $kqemu = "yes" -a $linux = "yes" ; then
+-# find the kernel path
+-if test -z "$kernel_path" ; then
+-kernel_version=`uname -r`
+-kernel_path="/lib/modules/$kernel_version/build"
+-if test '!' -d "$kernel_path/include" ; then
+-    kernel_path="/usr/src/linux"
+-    if test '!' -d "$kernel_path/include" ; then
+-        echo "Could not find kernel includes in /lib/modules or /usr/src/linux - cannot build the kqemu module"
+-        kqemu="no"
+-    fi
+-fi
+-fi
+-
+ if test $kqemu = "yes" ; then
+-# test that the kernel config is present
+-if test '!' -f "$kernel_path/Makefile" ; then
+-    echo "No Makefile file present in $kernel_path - kqemu cannot be built"
+-    kqemu="no"
+-fi
+-
+ # find build system (2.6 or legacy)
+ kbuild26="yes"
+-if grep -q "PATCHLEVEL = 4" $kernel_path/Makefile ; then
+-kbuild26="no"
+-fi
+ fi # kqemu
+-fi # kqemu and linux
+-
+-
+ echo "Install prefix    $prefix"
+ echo "BIOS directory    $datadir"
+ echo "binary directory  $bindir"
diff --git a/qemu-gtk/callbacks.c b/qemu-gtk/callbacks.c
deleted file mode 100644 (file)
index 14b077d..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include <gtk/gtk.h>
-
-#include "callbacks.h"
-#include "interface.h"
-#include "support.h"
-#include "vl.h"
-
-
-void
-on_nouveau1_activate                   (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on_ouvrir1_activate                    (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on_enregistrer1_activate               (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on_enregistrer_sous1_activate          (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on_fermer1_activate                    (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on_quitter1_activate                   (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on_couper1_activate                    (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on_copier1_activate                    (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on_coller1_activate                    (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on_supprimer1_activate                 (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on_preferences1_activate               (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on_machine1_activate                   (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on_run1_activate                       (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on_run_in_a_snapshot1_activate         (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on_pause2_activate                     (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-       vm_stop(EXCP_INTERRUPT);
-}
-
-
-void
-on_continue1_activate                  (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-       vm_start();
-}
-
-
-void
-on_reset1_activate                     (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-       qemu_system_reset_request();
-}
-
-
-void
-on_shutdown1_activate                  (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-       qemu_system_shutdown_request();
-}
-
-
-void
-on_zoom1_activate                      (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
-
-void
-on____propos1_activate                 (GtkMenuItem     *menuitem,
-                                        gpointer         user_data)
-{
-
-}
-
diff --git a/qemu-gtk/callbacks.h b/qemu-gtk/callbacks.h
deleted file mode 100644 (file)
index b5d8d1f..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-#include <gtk/gtk.h>
-
-
-void
-on_nouveau1_activate                   (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_ouvrir1_activate                    (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_enregistrer1_activate               (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_enregistrer_sous1_activate          (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_fermer1_activate                    (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_quitter1_activate                   (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_couper1_activate                    (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_copier1_activate                    (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_coller1_activate                    (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_supprimer1_activate                 (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_preferences1_activate               (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_machine1_activate                   (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_run1_activate                       (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_run_in_a_snapshot1_activate         (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_pause2_activate                     (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_continue1_activate                  (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_reset1_activate                     (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_shutdown1_activate                  (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on_zoom1_activate                      (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
-
-void
-on____propos1_activate                 (GtkMenuItem     *menuitem,
-                                        gpointer         user_data);
diff --git a/qemu-gtk/fullscreen.h b/qemu-gtk/fullscreen.h
deleted file mode 100644 (file)
index 3802b40..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-/* fullscreen defines */
-
-int fullscreen_init(void);
-int fullscreen_switch(int x, int y, int w, int h);
-int fullscreen_reset(void);
-void fullscreen_cleanup(void);
diff --git a/qemu-gtk/gdk_keysym.h b/qemu-gtk/gdk_keysym.h
deleted file mode 100644 (file)
index 2fab099..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-#include <gdk/gdkkeysyms.h>
-
-typedef struct {
-       const char* name;
-       int keysym;
-} name2keysym_t;
-static name2keysym_t name2keysym[]={
-/* ascii */
-    { "space",                0x020},
-    { "exclam",               0x021},
-    { "quotedbl",             0x022},
-    { "numbersign",           0x023},
-    { "dollar",               0x024},
-    { "percent",              0x025},
-    { "ampersand",            0x026},
-    { "apostrophe",           0x027},
-    { "parenleft",            0x028},
-    { "parenright",           0x029},
-    { "asterisk",             0x02a},
-    { "plus",                 0x02b},
-    { "comma",                0x02c},
-    { "minus",                0x02d},
-    { "period",               0x02e},
-    { "slash",                0x02f},
-    { "0",                    0x030},
-    { "1",                    0x031},
-    { "2",                    0x032},
-    { "3",                    0x033},
-    { "4",                    0x034},
-    { "5",                    0x035},
-    { "6",                    0x036},
-    { "7",                    0x037},
-    { "8",                    0x038},
-    { "9",                    0x039},
-    { "colon",                0x03a},
-    { "semicolon",            0x03b},
-    { "less",                 0x03c},
-    { "equal",                0x03d},
-    { "greater",              0x03e},
-    { "question",             0x03f},
-    { "at",                   0x040},
-    { "A",                    0x041},
-    { "B",                    0x042},
-    { "C",                    0x043},
-    { "D",                    0x044},
-    { "E",                    0x045},
-    { "F",                    0x046},
-    { "G",                    0x047},
-    { "H",                    0x048},
-    { "I",                    0x049},
-    { "J",                    0x04a},
-    { "K",                    0x04b},
-    { "L",                    0x04c},
-    { "M",                    0x04d},
-    { "N",                    0x04e},
-    { "O",                    0x04f},
-    { "P",                    0x050},
-    { "Q",                    0x051},
-    { "R",                    0x052},
-    { "S",                    0x053},
-    { "T",                    0x054},
-    { "U",                    0x055},
-    { "V",                    0x056},
-    { "W",                    0x057},
-    { "X",                    0x058},
-    { "Y",                    0x059},
-    { "Z",                    0x05a},
-    { "bracketleft",          0x05b},
-    { "backslash",            0x05c},
-    { "bracketright",         0x05d},
-    { "asciicircum",          0x05e},
-    { "underscore",           0x05f},
-    { "grave",                0x060},
-    { "a",                    0x061},
-    { "b",                    0x062},
-    { "c",                    0x063},
-    { "d",                    0x064},
-    { "e",                    0x065},
-    { "f",                    0x066},
-    { "g",                    0x067},
-    { "h",                    0x068},
-    { "i",                    0x069},
-    { "j",                    0x06a},
-    { "k",                    0x06b},
-    { "l",                    0x06c},
-    { "m",                    0x06d},
-    { "n",                    0x06e},
-    { "o",                    0x06f},
-    { "p",                    0x070},
-    { "q",                    0x071},
-    { "r",                    0x072},
-    { "s",                    0x073},
-    { "t",                    0x074},
-    { "u",                    0x075},
-    { "v",                    0x076},
-    { "w",                    0x077},
-    { "x",                    0x078},
-    { "y",                    0x079},
-    { "z",                    0x07a},
-    { "braceleft",            0x07b},
-    { "bar",                  0x07c},
-    { "braceright",           0x07d},
-    { "asciitilde",           0x07e},
-
-/* latin 1 extensions */
-{ "nobreakspace",         0x0a0},
-{ "exclamdown",           0x0a1},
-{ "cent",                0x0a2},
-{ "sterling",             0x0a3},
-{ "currency",             0x0a4},
-{ "yen",                  0x0a5},
-{ "brokenbar",            0x0a6},
-{ "section",              0x0a7},
-{ "diaeresis",            0x0a8},
-{ "copyright",            0x0a9},
-{ "ordfeminine",          0x0aa},
-{ "guillemotleft",        0x0ab},
-{ "notsign",              0x0ac},
-{ "hyphen",               0x0ad},
-{ "registered",           0x0ae},
-{ "macron",               0x0af},
-{ "degree",               0x0b0},
-{ "plusminus",            0x0b1},
-{ "twosuperior",          0x0b2},
-{ "threesuperior",        0x0b3},
-{ "acute",                0x0b4},
-{ "mu",                   0x0b5},
-{ "paragraph",            0x0b6},
-{ "periodcentered",       0x0b7},
-{ "cedilla",              0x0b8},
-{ "onesuperior",          0x0b9},
-{ "masculine",            0x0ba},
-{ "guillemotright",       0x0bb},
-{ "onequarter",           0x0bc},
-{ "onehalf",              0x0bd},
-{ "threequarters",        0x0be},
-{ "questiondown",         0x0bf},
-{ "Agrave",               0x0c0},
-{ "Aacute",               0x0c1},
-{ "Acircumflex",          0x0c2},
-{ "Atilde",               0x0c3},
-{ "Adiaeresis",           0x0c4},
-{ "Aring",                0x0c5},
-{ "AE",                   0x0c6},
-{ "Ccedilla",             0x0c7},
-{ "Egrave",               0x0c8},
-{ "Eacute",               0x0c9},
-{ "Ecircumflex",          0x0ca},
-{ "Ediaeresis",           0x0cb},
-{ "Igrave",               0x0cc},
-{ "Iacute",               0x0cd},
-{ "Icircumflex",          0x0ce},
-{ "Idiaeresis",           0x0cf},
-{ "ETH",                  0x0d0},
-{ "Eth",                  0x0d0},
-{ "Ntilde",               0x0d1},
-{ "Ograve",               0x0d2},
-{ "Oacute",               0x0d3},
-{ "Ocircumflex",          0x0d4},
-{ "Otilde",               0x0d5},
-{ "Odiaeresis",           0x0d6},
-{ "multiply",             0x0d7},
-{ "Ooblique",             0x0d8},
-{ "Oslash",               0x0d8},
-{ "Ugrave",               0x0d9},
-{ "Uacute",               0x0da},
-{ "Ucircumflex",          0x0db},
-{ "Udiaeresis",           0x0dc},
-{ "Yacute",               0x0dd},
-{ "THORN",                0x0de},
-{ "Thorn",                0x0de},
-{ "ssharp",               0x0df},
-{ "agrave",               0x0e0},
-{ "aacute",               0x0e1},
-{ "acircumflex",          0x0e2},
-{ "atilde",               0x0e3},
-{ "adiaeresis",           0x0e4},
-{ "aring",                0x0e5},
-{ "ae",                   0x0e6},
-{ "ccedilla",             0x0e7},
-{ "egrave",               0x0e8},
-{ "eacute",               0x0e9},
-{ "ecircumflex",          0x0ea},
-{ "ediaeresis",           0x0eb},
-{ "igrave",               0x0ec},
-{ "iacute",               0x0ed},
-{ "icircumflex",          0x0ee},
-{ "idiaeresis",           0x0ef},
-{ "eth",                  0x0f0},
-{ "ntilde",               0x0f1},
-{ "ograve",               0x0f2},
-{ "oacute",               0x0f3},
-{ "ocircumflex",          0x0f4},
-{ "otilde",               0x0f5},
-{ "odiaeresis",           0x0f6},
-{ "division",             0x0f7},
-{ "oslash",               0x0f8},
-{ "ooblique",             0x0f8},
-{ "ugrave",               0x0f9},
-{ "uacute",               0x0fa},
-{ "ucircumflex",          0x0fb},
-{ "udiaeresis",           0x0fc},
-{ "yacute",               0x0fd},
-{ "thorn",                0x0fe},
-{ "ydiaeresis",           0x0ff},
-{"EuroSign", GDK_EuroSign},
-
-    /* modifiers */
-{"Control_L", GDK_Control_L},
-{"Control_R", GDK_Control_R},
-{"Alt_L", GDK_Alt_L},
-{"Alt_R", GDK_Alt_R},
-{"Caps_Lock", GDK_Caps_Lock},
-{"Meta_L", GDK_Meta_L},
-{"Meta_R", GDK_Meta_R},
-{"Shift_L", GDK_Shift_L},
-{"Shift_R", GDK_Shift_R},
-{"Super_L", GDK_Super_L},
-{"Super_R", GDK_Super_R},
-
-    /* special keys */
-{"BackSpace", GDK_BackSpace},
-{"Tab", GDK_Tab},
-{"Return", GDK_Return},
-{"Right", GDK_Right},
-{"Left", GDK_Left},
-{"Up", GDK_Up},
-{"Down", GDK_Down},
-{"Page_Down", GDK_Page_Down},
-{"Page_Up", GDK_Page_Up},
-{"Insert", GDK_Insert},
-{"Delete", GDK_Delete},
-{"Home", GDK_Home},
-{"End", GDK_End},
-{"Scroll_Lock", GDK_Scroll_Lock},
-{"F1", GDK_F1},
-{"F2", GDK_F2},
-{"F3", GDK_F3},
-{"F4", GDK_F4},
-{"F5", GDK_F5},
-{"F6", GDK_F6},
-{"F7", GDK_F7},
-{"F8", GDK_F8},
-{"F9", GDK_F9},
-{"F10", GDK_F10},
-{"F11", GDK_F11},
-{"F12", GDK_F12},
-{"F13", GDK_F13},
-{"F14", GDK_F14},
-{"F15", GDK_F15},
-{"Sys_Req", GDK_Sys_Req},
-{"KP_0", GDK_KP_0},
-{"KP_1", GDK_KP_1},
-{"KP_2", GDK_KP_2},
-{"KP_3", GDK_KP_3},
-{"KP_4", GDK_KP_4},
-{"KP_5", GDK_KP_5},
-{"KP_6", GDK_KP_6},
-{"KP_7", GDK_KP_7},
-{"KP_8", GDK_KP_8},
-{"KP_9", GDK_KP_9},
-{"KP_Add", GDK_KP_Add},
-{"KP_Decimal", GDK_KP_Decimal},
-{"KP_Divide", GDK_KP_Divide},
-{"KP_Enter", GDK_KP_Enter},
-{"KP_Equal", GDK_KP_Equal},
-{"KP_Multiply", GDK_KP_Multiply},
-{"KP_Subtract", GDK_KP_Subtract},
-{"help", GDK_Help},
-{"Menu", GDK_Menu},
-{"Power", GDK_VoidSymbol},
-{"Print", GDK_Print},
-{"Mode_switch", GDK_Mode_switch},
-{"Multi_Key", GDK_Multi_key},
-{"Num_Lock", GDK_Num_Lock},
-{"Pause", GDK_Pause},
-{"Escape", GDK_Escape},
-
-{0,0},
-};
diff --git a/qemu-gtk/gdk_set_window_pointer.c b/qemu-gtk/gdk_set_window_pointer.c
deleted file mode 100644 (file)
index 692eb7d..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* TODO: figure out how to handle linux framebuffer case - need to call the gdk-fb specific handle_mouse_movement() function in gdkmouse-fb.c ... that gets ugly fast .. */
-
-#ifndef _WIN32
-
-#include <gdk/gdk.h>
-#include <gdk/gdkx.h>
-#include <X11/X.h>
-
- GdkWindow*
-gdk_window_set_pointer (GdkWindow       *window,
-                       gint            x,
-                       gint            y)
-{
-  GdkWindow *return_val;
-
-  return_val = NULL;
-  XWarpPointer (GDK_WINDOW_XDISPLAY(window), None, GDK_WINDOW_XID(window), 0, 0, 0, 0, x, y);
-
-  return return_val;
-}
-
-#else
-
-/* untested code based on MSDN library code... URL is :
-
-                  http://msdn.microsoft.com/library/default.asp?url=/library/
-                  en-us/winui/winui/windowsuserinterface/resources/cursors/
-                  usingcursors.asp         
-
-Someone who codes on Windows want to tell me how to actually make this work??
-
-*/
-
-#include <gdk/gdk.h>
-#include <gdk/gdkwin32.h>
-#include <windows.h>
-
- GdkWindow*
-gdk_window_set_pointer (GdkWindow       *window,
-                       gint            x,
-                       gint            y)
-{
-       GdkWindow *return_val;
-       POINT pt;
-       pt.x = x;
-       pt.y = y;
-       ClientToScreen(GDK_WINDOW_HWND(window), &pt);
-       SetCursorPos(pt.x, pt.y);
-       return_val = NULL;
-       return return_val;
-}
-
-#endif
-
diff --git a/qemu-gtk/gtk2.c b/qemu-gtk/gtk2.c
deleted file mode 100644 (file)
index 35d24f3..0000000
+++ /dev/null
@@ -1,946 +0,0 @@
-/*
- * QEMU GTK2 display driver
- * based on SDL driver by Fabrice
- * 
- * Copyright (c) 2005 Jim Brown
- * 
- * 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 <gtk/gtk.h>
-#include <gdk/gdk.h>
-
-#include "fullscreen.h"
-
-/* define our own bitshift enums to allow qemugtk to know difference between left and right alt - something gtk doesnt provide in its modifiers mask. this uses qemu's own modifier_state[] map in order to guess correctly */
-typedef enum
-{
-       gtkshiftleft = 1 << 0,
-       gtkshiftright = 1 << 1,
-       gtkcontrolleft = 1 << 2,
-       gtkcontrolright = 1 << 3,
-       gtkaltleft = 1 << 4,
-       gtkaltright = 1 << 5,
-       gtkcapslock = 1 << 6
-} gtk2keymod;
-
-
-static GtkWidget *window, *swindow;
-static GtkWidget *event_port, *menubar;
-static GdkImage *image=NULL;
-static GdkCursor *invisible_cursor;
-static int ox = 0, oy = 0;
-static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
-static int gui_rgrab; /* if true, all keyboard/mouse events are grabbed */
-static int last_vm_running;
-static int gui_saved_grab;
-static int gui_fullscreen;
-static int gui_key_modifier_pressed;
-static int gui_keysym;
-static int gui_fullscreen_initial_grab;
-static int gui_grab_code = gtkaltleft | gtkcontrolleft;
-static uint8_t modifiers_state[256];
-static int window_resize = 0;
-static unsigned int cw, ch;
-static gint win_x, win_y, win_w, win_h;
-static GtkWidget * box; /* because GtkWindow/GtkBin holds only one widget */
-
-static gboolean gtk2_expose(GtkWidget *wid, GdkEventExpose *event)
-{
-    if (gui_fullscreen && wid == event_port) return FALSE;
-    if (!gui_fullscreen && wid == window) return FALSE;
-    gdk_draw_image(wid->window, wid->style->fg_gc[GTK_WIDGET_STATE(wid)], image, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height);
-    return TRUE;
-}
-
-static void gtk2_update(DisplayState *ds, int x, int y, int w, int h)
-{
-    //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
-    GdkEventExpose ev;
-    ev.area.x = x;
-    ev.area.y = y;
-    ev.area.width = w;
-    ev.area.height = h;
-    /* catch the first resize done by the init function - make sure we don't **
-    ** try to draw an image until screen has been finalized/realized/etc */
-    if (event_port->window != NULL)
-    {
-       if (gui_fullscreen)
-           gtk2_expose(window, &ev);
-       else
-           gtk2_expose(event_port, &ev);
-    }
-}
-
-static void gtk2_resize(DisplayState *ds, int w, int h)
-{
-
-    //    printf(" resizing to %d %d\n", w, h);
-
-    if (gui_fullscreen)
-    {
-       if (cw != w || ch != h)
-       {
-           fullscreen_switch(win_x, win_y, w, h); /* changing video modes */
-/* apparently GTK enjoys moving static windows all over the place while
-they are being resized - so we have to be tricky */
-           //gtk_window_move(GTK_WINDOW(window), win_x, win_y);
-           //gtk_window_move(GTK_WINDOW(window), 0, 0);
-           gdk_window_move_resize(window->window, 0, 0, w, h);
-       }
-    }
-
-    cw = w; ch = h;
-
-    if (image)
-        g_object_unref(image);
-
-/* gdk_visual_get_best_with_depth() ??? but then how to paint onto window? */
-    image = gdk_image_new(GDK_IMAGE_NORMAL, gdk_visual_get_system(), w, h);
-    gdk_image_set_colormap(image, gdk_colormap_get_system());
-
-    gtk_widget_set_size_request(event_port, w, h);
-    if (window_resize)
-       gdk_window_move_resize(window->window, win_x, win_y, w+25, h+50);
-
-    ds->data = image->mem;
-    ds->linesize = image->bpl;
-    ds->depth = image->bits_per_pixel;
-    ds->width = w;
-    ds->height = h;
-    gtk2_update(ds, 0, 0, w, h);
-}
-
-static gboolean gtk2_config(GtkWidget *wid, GdkEventConfigure *ev, DisplayState *ds)
-{
-    if (!gui_fullscreen)
-    {
-       win_x = ev->x;
-       win_y = ev->y;
-       win_w = ev->width;
-       win_h = ev->height;
-    }
-    return FALSE;
-}
-
-/* generic keyboard conversion */
-
-#include "gdk_keysym.h"
-#include "keymaps.c"
-
-static kbd_layout_t *kbd_layout = NULL;
-
-static uint8_t gtk2_keyevent_to_keycode_generic(const GdkEventKey *ev)
-{
-    int keysym;
-    /* workaround for X11+SDL bug with AltGR - is it still needed for Gtk2? */
-    keysym = ev->keyval;
-    if (keysym == 0 && ev->hardware_keycode == 113)
-       keysym = GDK_Mode_switch;
-    return keysym2scancode(kbd_layout, keysym);
-}
-
-/* specific keyboard conversions from scan codes */
-
-#if defined(_WIN32)
-
-#include <windows.h>
-
-static UINT vk2scan(UINT vk)
-{
-       return MapVirtualKey(vk,0);
-}
-static uint8_t gtk2_keyevent_to_keycode(const GdkEventKey *ev)
-{   
-    return (uint8_t)vk2scan((UINT)(ev->hardware_keycode));
-}
-
-#else
-
-static const uint8_t x_keycode_to_pc_keycode[61] = {
-   0xc7,      /*  97  Home   */
-   0xc8,      /*  98  Up     */
-   0xc9,      /*  99  PgUp   */
-   0xcb,      /* 100  Left   */
-   0x4c,        /* 101  KP-5   */
-   0xcd,      /* 102  Right  */
-   0xcf,      /* 103  End    */
-   0xd0,      /* 104  Down   */
-   0xd1,      /* 105  PgDn   */
-   0xd2,      /* 106  Ins    */
-   0xd3,      /* 107  Del    */
-   0x9c,      /* 108  Enter  */
-   0x9d,      /* 109  Ctrl-R */
-   0x0,       /* 110  Pause  */
-   0xb7,      /* 111  Print  */
-   0xb5,      /* 112  Divide */
-   0xb8,      /* 113  Alt-R  */
-   0xc6,      /* 114  Break  */   
-   0xdb,         /* 115 windows left button */
-   0xdc,         /* 116 windows right button */
-   0xdd,         /* 117 right menu button */
-   0x0,         /* 118 */
-   0x0,         /* 119 */
-   0x70,         /* 120 Hiragana_Katakana */
-   0x0,         /* 121 */
-   0x0,         /* 122 */
-   0x73,         /* 123 backslash */
-   0x0,         /* 124 */
-   0x0,         /* 125 */
-   0x0,         /* 126 */
-   0x0,         /* 127 */
-   0x0,         /* 128 */
-   0x79,         /* 129 Henkan */
-   0x0,         /* 130 */
-   0x7b,         /* 131 Muhenkan */
-   0x0,         /* 132 */
-   0x7d,         /* 133 Yen */
-   0x0,         /* 134 */
-   0x0,         /* 135 */
-   0x47,         /* 136 KP_7 */
-   0x48,         /* 137 KP_8 */
-   0x49,         /* 138 KP_9 */
-   0x4b,         /* 139 KP_4 */
-   0x4c,         /* 140 KP_5 */
-   0x4d,         /* 141 KP_6 */
-   0x4f,         /* 142 KP_1 */
-   0x50,         /* 143 KP_2 */
-   0x51,         /* 144 KP_3 */
-   0x52,         /* 145 KP_0 */
-   0x53,         /* 146 KP_. */
-   0x47,         /* 147 KP_HOME */
-   0x48,         /* 148 KP_UP */
-   0x49,         /* 149 KP_PgUp */
-   0x4b,         /* 150 KP_Left */
-   0x4c,         /* 151 KP_ */
-   0x4d,         /* 152 KP_Right */
-   0x4f,         /* 153 KP_End */
-   0x50,         /* 154 KP_Down */
-   0x51,         /* 155 KP_PgDn */
-   0x52,         /* 156 KP_Ins */
-   0x53,         /* 157 KP_Del */
-};
-
-static uint8_t gtk2_keyevent_to_keycode(const GdkEventKey *ev)
-{
-    int keycode;
-
-    keycode = ev->hardware_keycode;
-
-    if (keycode < 9) {
-       keycode = 0;
-    } else if (keycode < 97) {
-       keycode -= 8; /* just an offset */
-    } else if (keycode < 158) {
-       /* use conversion table */
-       keycode = x_keycode_to_pc_keycode[keycode - 97];
-    } else {
-       keycode = 0;
-    }
-    return keycode;
-}
-
-#endif
-
-static void reset_keys(void)
-{
-    int i;
-    for(i = 0; i < 256; i++) {
-       if (modifiers_state[i]) {
-           if (i & 0x80)
-               kbd_put_keycode(0xe0);
-           kbd_put_keycode(i | 0x80);
-           modifiers_state[i] = 0;
-       }
-    }
-}
-
-/* convert GDK modifiers and invoke ugly hack to distinguish
-between left and right shift/control/alt */
-static guint gtk2_GetModState(const GdkEventKey *ev)
-{
-       guint key = 0, keyval = ev->keyval, state = ev->state;
-       switch(keyval)
-       {
-               case GDK_Shift_L:
-                       if (ev->type != GDK_KEY_RELEASE)
-                               key |= gtkshiftleft;
-                       keyval = 1;
-                       break;
-               case GDK_Shift_R:
-                       if (ev->type != GDK_KEY_RELEASE)
-                               key |= gtkshiftright;
-                       keyval = 1;
-                       break;
-               case GDK_Control_L:
-                       if (ev->type != GDK_KEY_RELEASE)
-                               key |= gtkcontrolleft;
-                       keyval = 2;
-                       break;
-               case GDK_Control_R:
-                       if (ev->type != GDK_KEY_RELEASE)
-                               key |= gtkcontrolright;
-                       keyval = 2;
-                       break;
-               case GDK_Alt_L:
-                       if (ev->type != GDK_KEY_RELEASE)
-                               key |= gtkaltleft;
-                       keyval = 3;
-                       break;
-               case GDK_Alt_R:
-                       if (ev->type != GDK_KEY_RELEASE)
-                               key |= gtkaltright;
-                       keyval = 3;
-                       break;
-               case GDK_Caps_Lock:
-                       if (ev->type != GDK_KEY_RELEASE)
-                               key |= gtkcapslock;
-                       keyval = 4;
-                       break;
-               default:
-                       keyval = 0;
-                       break;
-       }
-       if (keyval != 1 && (state & GDK_SHIFT_MASK))
-       {
-               if (modifiers_state[0x2a])
-                       key |= gtkshiftleft;
-               if (modifiers_state[0x36])
-                       key |= gtkshiftright;
-       }
-       if (keyval != 2 && (state & GDK_CONTROL_MASK))
-       {
-               if (modifiers_state[0x1d])
-                       key |= gtkcontrolleft;
-               if (modifiers_state[0x9d])
-                       key |= gtkcontrolright;
-       }
-       if (keyval != 3 && (state & GDK_MOD1_MASK)) /* fixme: need to do a check to make sure that alt is mapped to GDK_MOD1_MASK in the GDK_Keymap */
-       {
-               if (modifiers_state[0x38])
-                       key |= gtkaltleft;
-               if (modifiers_state[0xb8])
-                       key |= gtkaltright;
-       }
-       if (keyval != 4 && (state & GDK_LOCK_MASK))
-               key |= gtkcapslock;
-       return key;
-}
-
-static void gtk2_process_key(GdkEventKey *ev)
-{
-    int keycode, v;
-
-    if (ev->keyval == GDK_Pause) {
-       /* specific case */
-       v = 0;
-       if (ev->type == GDK_KEY_RELEASE)
-           v |= 0x80;
-       kbd_put_keycode(0xe1);
-       kbd_put_keycode(0x1d | v);
-       kbd_put_keycode(0x45 | v);
-       return;
-    }
-
-    if (kbd_layout) {
-       keycode = gtk2_keyevent_to_keycode_generic(ev);
-    } else {
-       keycode = gtk2_keyevent_to_keycode(ev);
-    }
-
-    switch(keycode) {
-    case 0x00:
-       /* sent when leaving window: reset the modifiers state */
-       reset_keys();
-       return;
-    case 0x2a:                          /* Left Shift */
-    case 0x36:                          /* Right Shift */
-    case 0x1d:                          /* Left CTRL */
-    case 0x9d:                          /* Right CTRL */
-    case 0x38:                          /* Left ALT */
-    case 0xb8:                         /* Right ALT */
-       if (ev->type == GDK_KEY_RELEASE)
-           modifiers_state[keycode] = 0;
-       else
-           modifiers_state[keycode] = 1;
-       break;
-    case 0x45: /* num lock */
-    case 0x3a: /* caps lock */
-       /* GTK does send the key up event, so we dont generate it */
-       /*kbd_put_keycode(keycode);
-       kbd_put_keycode(keycode | 0x80);
-       return;*/
-       break;
-    }
-
-    /* now send the key code */
-    if (keycode & 0x80)
-       kbd_put_keycode(0xe0);
-    if (ev->type == GDK_KEY_RELEASE)
-       kbd_put_keycode(keycode | 0x80);
-    else
-       kbd_put_keycode(keycode & 0x7f);
-}
-
-static void gtk2_update_caption(void)
-{
-    char buf[1024];
-    strcpy(buf, "QEMU Gtk");
-    if (!vm_running) {
-       strcat(buf, " [Stopped]");
-    }
-    if (gui_grab) {
-       strcat(buf, " - Press Ctrl-Alt to exit grab");
-    }
-    gtk_window_set_title(GTK_WINDOW(window), buf);
-}
-
-/* what a nasty hack. this should be a part of the GDK, not external!!! */
-#include "gdk_set_window_pointer.c"
-
-static void gtk2_grab_start(void)
-{
-    gint y;
-    guint events;
-    GdkModifierType state; /* dummy var */
-    GtkWidget * grab;
-    if (gui_fullscreen) /* make sure grab is on correct x window */
-       grab = window;
-    else
-       grab = event_port;
-if (gui_rgrab || gui_fullscreen)
-{
-    events = GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK;
-    y = gdk_pointer_grab(grab->window, TRUE, events, grab->window, invisible_cursor, GDK_CURRENT_TIME);
-    if (y)
-       printf("GTK Warning - pointer grab failed!\n");
-    y = gdk_keyboard_grab(grab->window, TRUE, GDK_CURRENT_TIME);
-    if (y)
-       printf("GTK Warning - keyboard grab failed!\n");
-}
-    /* do a dummy read to avoid moving mouse - set ox and oy to stay in sync */
-    gdk_window_get_pointer(event_port->window, &ox, &oy, &state);
-    gui_grab = 1;
-    gtk2_update_caption();
-}
-
-static void gtk2_grab_end(void)
-{
-    GtkWidget * grab;
-    if (gui_fullscreen)
-       grab = window;
-    else
-       grab = event_port;
-if (gui_rgrab || gui_fullscreen)
-{
-    gdk_pointer_ungrab(GDK_CURRENT_TIME);
-    gdk_keyboard_ungrab(GDK_CURRENT_TIME);
-    gdk_window_set_pointer(grab->window, win_x, win_y);
-}
-    gui_grab = 0;
-    gtk2_update_caption();
-}
-
-static gboolean gtk2_send_mouse_event(GtkWidget *wid, GdkEvent *ev)
-{
-    int x, y, dx, dy, dz, state, buttons;
-    GtkWidget * grab;
-    if (gui_fullscreen) /* make sure grab is on correct x window */
-       grab = window;
-    else
-       grab = event_port;
-
-    if (gui_fullscreen && wid == event_port) return FALSE;
-    if (!gui_fullscreen && wid == window) return FALSE;
-    if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS)
-       return TRUE; /* double or triple click - superflurious - ignore */
-
-    if (gui_grab)
-    {
-
-    if (ev->type == GDK_MOTION_NOTIFY && ev->motion.is_hint)
-    {
-       gdk_window_get_pointer(ev->motion.window, &x, &y, (GdkModifierType*)&state);
-    }
-    else
-    {
-       x = ev->motion.x;
-       y = ev->motion.y;
-       /* scroll.state occupies a different position in the union */
-       if (ev->type == GDK_SCROLL)
-       state = ev->scroll.state;
-       else
-       state = ev->motion.state;
-    }
-
-    dx = x - ox;
-    dy = y - oy;
-    // prevent infinite looping - 2.6.X
-    if ((ev->type == GDK_MOTION_NOTIFY) && (dx == 0) && (dy == 0)) return TRUE;
-    dz = 0;
-    ox = x;
-    oy = y;
-
-    buttons = 0;
-    if ((state & GDK_BUTTON1_MASK))
-       buttons |= MOUSE_EVENT_LBUTTON;
-    if ((state & GDK_BUTTON3_MASK))
-       buttons |= MOUSE_EVENT_RBUTTON;
-    if ((state & GDK_BUTTON2_MASK))
-       buttons |= MOUSE_EVENT_MBUTTON;
-
-    if (ev->type == GDK_BUTTON_PRESS)
-    {
-       if (ev->button.button == 1)
-           buttons |= MOUSE_EVENT_LBUTTON;
-       if (ev->button.button == 3)
-           buttons |= MOUSE_EVENT_RBUTTON;
-       if (ev->button.button == 2)
-           buttons |= MOUSE_EVENT_MBUTTON;
-    }
-    else if (ev->type == GDK_BUTTON_RELEASE)
-    {
-    /* not sure if this is really necessary, but just to be on the safe side **
-    ** reset qemu's mask so that a button thats being released will be shown **
-    * missing from the mask (which lets the guest know the button was relased */
-       buttons = 0;
-
-       if ((state & GDK_BUTTON1_MASK) && ev->button.button != 1)
-           buttons |= MOUSE_EVENT_LBUTTON;
-       if ((state & GDK_BUTTON3_MASK) && ev->button.button != 3)
-           buttons |= MOUSE_EVENT_RBUTTON;
-       if ((state & GDK_BUTTON2_MASK) && ev->button.button != 2)
-           buttons |= MOUSE_EVENT_MBUTTON;
-    }
-    else if (ev->type == GDK_SCROLL)
-    {
-       /* test wheel - copied from Sebastien Bechet's gtk.c */
-       if (ev->scroll.direction == GDK_SCROLL_UP)
-           dz--;
-       if (ev->scroll.direction == GDK_SCROLL_DOWN)
-           dz++;
-    }
-
-    if ((ev->type == GDK_MOTION_NOTIFY) && (gui_rgrab || gui_fullscreen))
-    {
-       /* wrap the x,y coordinates back onto the window */
-       if (ev->motion.x <= (cw/4))
-           x = ((3*cw/4)-1);
-       if (ev->motion.y <= (ch/4))
-           y = ((3*ch/4)-1);
-       if (ev->motion.x >= (3*cw/4))
-           x = (cw/4)+1;
-       if (ev->motion.y >= (3*ch/4))
-           y = (ch/4)+1;
-
-       /* make internal mouse move invisible */
-       ox = x;
-       oy = y;
-
-       gdk_window_set_pointer(grab->window, (gint)x, (gint)y);
-    }
-
-    kbd_mouse_event(dx, dy, dz, buttons);
-
-    }
-    else
-    {
-
-    if (ev->type == GDK_BUTTON_PRESS && ev->button.button == 1)
-    {
-       /* start grabbing all events */
-       gtk2_grab_start();
-    }
-
-    }
-    return TRUE;
-}
-
-static void toggle_full_screen(DisplayState *ds)
-{
-    gui_fullscreen = !gui_fullscreen;
-    gtk2_resize(ds, image->width, image->height);
-    if (gui_fullscreen) {
-       gui_saved_grab = gui_grab;
-       gtk2_grab_start();
-       gtk_window_get_position(GTK_WINDOW(window), &win_x, &win_y);
-       gdk_window_move_resize(window->window, 0, 0, ds->width, ds->height);
-       gtk_widget_hide(box);
-       fullscreen_switch(win_x, win_y, ds->width, ds->height);
-    } else {
-       fullscreen_reset();
-       gdk_window_move_resize(window->window, win_x, win_y, win_w, win_h);
-       gui_fullscreen = !gui_fullscreen;
-       if (!gui_saved_grab)
-           gtk2_grab_end();
-       gui_fullscreen = !gui_fullscreen;
-       gtk_widget_show(box);
-    }
-    vga_invalidate_display();
-    vga_update_display();
-}
-
-static gboolean gtk2_key_press(GtkWidget *wid, GdkEventKey *ev, DisplayState *ds)
-{
-       int mod_state, internal_key = 0;
-           if (ev->type == GDK_KEY_PRESS) {
-               mod_state = (gtk2_GetModState(ev) & (int)gui_grab_code) == (int)gui_grab_code;
-               gui_key_modifier_pressed = mod_state;
-               if (gui_key_modifier_pressed) {
-                   int keycode;
-                   internal_key = 1;
-                   keycode = gtk2_keyevent_to_keycode(ev);
-                   switch(keycode) {
-                   case 0x21: /* 'f' key on US keyboard */
-                       toggle_full_screen(ds);
-                       gui_keysym = 1;
-                       break;
-                   case 0x02 ... 0x0a: /* '1' to '9' keys */ 
-                       console_select(keycode - 0x02);
-                       if (is_active_console(vga_console)) {
-                           /* tell the vga console to redisplay itself */
-                           vga_invalidate_display();
-                       } else {
-                           /* display grab if going to a text console */
-                           if (gui_grab)
-                               gtk2_grab_end();
-                       }
-                       gui_keysym = 1;
-                       break;
-                   default:
-                       break;
-                   }
-               } else if (!is_active_console(vga_console)) {
-                   int keysym;
-                   keysym = 0;
-                   if (ev->state & GDK_CONTROL_MASK) {
-                       switch(ev->keyval) {
-                       case GDK_Up: keysym = QEMU_KEY_CTRL_UP; break;
-                       case GDK_Down: keysym = QEMU_KEY_CTRL_DOWN; break;
-                       case GDK_Left: keysym = QEMU_KEY_CTRL_LEFT; break;
-                       case GDK_Right: keysym = QEMU_KEY_CTRL_RIGHT; break;
-                       case GDK_Home: keysym = QEMU_KEY_CTRL_HOME; break;
-                       case GDK_End: keysym = QEMU_KEY_CTRL_END; break;
-                       case GDK_Page_Up: keysym = QEMU_KEY_CTRL_PAGEUP; break;
-                       case GDK_Page_Down: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
-                       default: break;
-                       }
-                   } else {
-                       switch(ev->keyval) {
-                       case GDK_Up: keysym = QEMU_KEY_UP; break;
-                       case GDK_Down: keysym = QEMU_KEY_DOWN; break;
-                       case GDK_Left: keysym = QEMU_KEY_LEFT; break;
-                       case GDK_Right: keysym = QEMU_KEY_RIGHT; break;
-                       case GDK_Home: keysym = QEMU_KEY_HOME; break;
-                       case GDK_End: keysym = QEMU_KEY_END; break;
-                       case GDK_Page_Up: keysym = QEMU_KEY_PAGEUP; break;
-                       case GDK_Page_Down: keysym = QEMU_KEY_PAGEDOWN; break;
-                       case GDK_BackSpace: keysym = QEMU_KEY_BACKSPACE; break;
-                       case GDK_Delete: keysym = QEMU_KEY_DELETE; break;
-                       default: break;
-                       }
-                   }
-                   if (keysym) {
-                       kbd_put_keysym(keysym);
-                   } /*else if (ev->key.keysym.unicode != 0) {
-                       kbd_put_keysym(ev->key.keysym.unicode);
-                   }*/
-               }
-           } else if (ev->type == GDK_KEY_RELEASE) {
-               mod_state = (gtk2_GetModState(ev) & gui_grab_code);
-               if (!mod_state) {
-                   if (gui_key_modifier_pressed) {
-                       if (gui_keysym == 0) {
-                           /* exit/enter grab if pressing Ctrl-Alt */
-                           if (!gui_grab)
-                               gtk2_grab_start();
-                           else
-                               gtk2_grab_end();
-                           /* SDL does not send back all the
-                              modifiers key, so we must correct it */
-                           reset_keys();
-                           return TRUE;
-                       }
-                       gui_key_modifier_pressed = 0;
-                       gui_keysym = 0;
-                       internal_key = 1;
-                   }
-               }
-           }
-           if (is_active_console(vga_console) && !internal_key) 
-               gtk2_process_key(ev);
-            else if (internal_key && ev->type == GDK_KEY_RELEASE)
-            {
-                modifiers_state[0x38] = 0;
-                modifiers_state[0x1d] = 0;
-                kbd_put_keycode(0x38 | 0x80);
-                kbd_put_keycode(0x1d | 0x80);
-            }
-            else if (internal_key && ev->type == GDK_KEY_PRESS)
-            {
-                modifiers_state[0x38] = 1;
-                modifiers_state[0x1d] = 1;
-            }
-       return TRUE;
-}
-
-static void gtk2_refresh(DisplayState *ds)
-{
-    if (last_vm_running != vm_running) {
-       last_vm_running = vm_running;
-       gtk2_update_caption();
-    }
-    if (ds->data != image->mem)
-    {
-       ds->data = image->mem;
-    }
-
-    if (is_active_console(vga_console))                                         
-       vga_update_display();                                                   
-    while (gtk_events_pending())
-       gtk_main_iteration();
-}
-
-static void gtk2_cleanup(void) 
-{
-    if (gtk_main_level() != 0)
-       gtk_main_quit();
-    fullscreen_cleanup();
-}
-
-static gboolean gtk2_deletewin(void)
-{
-    /* signal qemu that its time to shut itself off - this is the place that we hook to trap attempts to close the main qemu window */
-    qemu_system_shutdown_request();
-    return FALSE;
-    return TRUE; /* dont close the window right away! give qemu time to think */
-}
-
-static void gtk2_destroy(void)
-{
-    /* ideally we would call a hook here so qemu could clean itself up */
-    gtk2_cleanup();
-}
-
-GtkWidget * gui_menu_add(const gchar * name)
-{
-    GtkWidget *menu, *menu_name;
-    menu = gtk_menu_new();
-    menu_name = gtk_menu_item_new_with_label(name);
-    gtk_menu_shell_append(GTK_MENU_SHELL(menubar), menu_name);
-    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_name), menu);
-    gtk_widget_show(menu_name);
-    return menu;
-}
-
-GtkWidget * gui_menuitem_add(GtkWidget * menu, const gchar * name, void (*item_handler)(void))
-{
-    GtkWidget *menu_item;
-    menu_item = gtk_menu_item_new_with_label(name);
-    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
-    g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(item_handler), NULL);
-    gtk_widget_show(menu_item);
-    return menu_item;
-}
-
-GtkWidget * gui_menusep_add(GtkWidget * menu)
-{
-    GtkWidget *menu_item;
-    menu_item = gtk_menu_item_new();
-    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
-    gtk_widget_show(menu_item);
-    return menu_item;
-}
-
-GtkWidget * gui_submenu_add(GtkWidget * menu, const gchar * name)
-{
-    GtkWidget *submenu, *menu_name;
-    submenu = gtk_menu_new();
-    menu_name = gtk_menu_item_new_with_label(name);
-    gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_name);
-    gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_name), submenu);
-    gtk_widget_show(menu_name);
-    return submenu;
-}
-
-void base_vc_switch(int i)
-{
-       console_select(i);
-       if (is_active_console(vga_console)) {
-           /* tell the vga console to redisplay itself */
-           vga_invalidate_display();
-       } else {
-           /* display grab if going to a text console */
-           if (gui_grab)
-               gtk2_grab_end();
-       }
-}
-void vc_guest(void) { base_vc_switch(0); }
-void vc_monitor(void) { base_vc_switch(1); }
-void vc_serial(void) { base_vc_switch(2); }
-void vc_para(void) { base_vc_switch(3); }
-void nop(void) {}
-
-void gtk2_menu_init(void)
-{
-       GtkWidget * menu;
-       menu = gui_menu_add("Monitor");
-       gui_menuitem_add(menu, "Reset", qemu_system_reset_request);
-       gui_menuitem_add(menu, "Quit", qemu_system_shutdown_request);
-       menu = gui_menu_add("Virtual Console");
-       menu = gui_submenu_add(menu, "Switch to");
-       gui_menuitem_add(menu, "Guest", vc_guest);
-       gui_menuitem_add(menu, "Monitor", vc_monitor);
-       gui_menuitem_add(menu, "Serial", vc_serial);
-       gui_menuitem_add(menu, "Parallel", vc_para);
-       menu = gui_menu_add("Help");
-       gui_menuitem_add(menu, "About", nop);
-}
-
-static int gargc=0;
-static char ** gargv=NULL;
-void gtk2_display_init(DisplayState *ds, int full_screen)
-{
-    int events;
-
-#if defined(__APPLE__)
-    /* always use generic keymaps */
-    if (!keyboard_layout)
-       keyboard_layout = "en-us";
-#endif
-    if(keyboard_layout) {
-       kbd_layout = init_keyboard_layout(keyboard_layout);
-       if (!kbd_layout)
-           exit(1);
-    }
-
-/* note - this strips the GTK-specific args after the main program is done with them */
-    if (!gtk_init_check (&gargc,&gargv))
-    {
-       fprintf(stderr, "Could not load GTK\n");
-       exit(0);
-    }
-    gui_rgrab = 0;
-    fullscreen_init();
-
-/* note: adding GDK_DRAG_* and GDK_DROP_* would provide a mechanism for supporting drag and drop between host and guest */
-    events = GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | GDK_SCROLL_MASK | GDK_STRUCTURE_MASK;
-
-    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    swindow = gtk_scrolled_window_new(NULL,NULL);
-    event_port = gtk_event_box_new();
-    menubar = gtk_menu_bar_new();
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow), GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
-    box = gtk_vbox_new(FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(window), box);
-    gtk_box_pack_start(GTK_BOX(box), menubar, FALSE, FALSE, 0);
-    gtk_box_pack_start(GTK_BOX(box), swindow, TRUE, TRUE, 0);
-    gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(swindow), event_port);
-    gtk_widget_set_events(event_port, events);
-    gtk_window_set_default_size(GTK_WINDOW(window), 720, 420);
-    gtk_widget_set_size_request(window, 0, 0);
-    gtk_widget_set_size_request(swindow, 720, 400);
-    gtk_widget_set_size_request(event_port, 720, 400);
-    gtk_window_set_gravity(GTK_WINDOW(window), GDK_GRAVITY_STATIC);
-    gtk2_menu_init();
-
-    g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(gtk2_deletewin), NULL);
-    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk2_destroy), NULL);
-    gtk_container_set_border_width(GTK_CONTAINER(window), 0);
-
-    g_signal_connect(G_OBJECT(window), "configure_event", G_CALLBACK(gtk2_config), NULL);
-    g_signal_connect(G_OBJECT(window), "expose_event", G_CALLBACK(gtk2_expose), NULL);
-    g_signal_connect(G_OBJECT(window), "motion_notify_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(window), "button_press_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(window), "button_release_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(window), "scroll_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(event_port), "expose_event", G_CALLBACK(gtk2_expose), NULL);
-    g_signal_connect(G_OBJECT(event_port), "motion_notify_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(event_port), "button_press_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(event_port), "button_release_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(event_port), "scroll_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(gtk2_key_press), ds);
-    g_signal_connect(G_OBJECT(window), "key_release_event", G_CALLBACK(gtk2_key_press), ds);
-
-    ds->dpy_update = gtk2_update;
-    ds->dpy_resize = gtk2_resize;
-    ds->dpy_refresh = gtk2_refresh;
-
-    gchar nullpixdata[1] = { 0 };
-    GdkColor nullcolor = { 0, 0, 0, 0 };
-    GdkPixmap *invis = gdk_bitmap_create_from_data(window->window, nullpixdata, 1, 1);
-    invisible_cursor = gdk_cursor_new_from_pixmap(invis, invis, &nullcolor, &nullcolor, 0, 0);
-
-    gtk2_resize(ds, 720, 400);
-    gtk2_update_caption();
-    gui_grab = 0;
-
-    gtk_widget_show(event_port);
-    gtk_widget_show(swindow);
-    gtk_widget_show(menubar);
-    gtk_widget_show(box);
-    gtk_widget_show(window);
-    if (full_screen) {
-       gui_fullscreen = 1;
-       gui_fullscreen_initial_grab = 1;
-       gtk2_grab_start();
-    }
-}
-
-/* we are allowed to look at the args, but not allowed to modify them
-with the exception that we have to remove args that are meant for us, as
-main qemu will not recognize them */
-void gui_checkargs(int * pargc, char *** pargv)
-{
-    int argc = *pargc;
-    char ** argv = *pargv;
-    char ** vargv;
-    int i, j = 0;
-    vargv = malloc(argc * sizeof(char*));
-    for (i = 0; i < argc; i++)
-    {
-        if (!strcmp(argv[i], "-window-resize-on"))
-       {
-               window_resize = 1;
-               (*pargc)--;
-       }
-        else if (!strcmp(argv[i], "-raw-grab"))
-       {
-               gui_rgrab = 1;
-               (*pargc)--;
-       }
-       else
-       {
-               vargv[j] = argv[i];
-               j++;
-       }
-    }
-    /* so lets hide them */
-    for (i = 0; i < *pargc; i++)
-    {
-       (*pargv)[i] = vargv[i];
-    }
-    if (argc != (*pargc)) (*pargv)[*pargc] = NULL;
-    free(vargv);
-    /* save a copy so we can pass them to gtk_init() later */
-    gargc = *pargc;
-    gargv = *pargv;
-}
-
diff --git a/qemu-gtk/gtk2gui.c b/qemu-gtk/gtk2gui.c
deleted file mode 100644 (file)
index 370730e..0000000
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- * QEMU GTK2 display driver
- * based on SDL driver by Fabrice
- * 
- * Copyright (c) 2005 Jim Brown
- * 
- * 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 <gtk/gtk.h>
-#include <gdk/gdk.h>
-
-#include "fullscreen.h"
-
-#include "interface.h"
-#include "callbacks.h"
-#include "support.h"
-
-/* define our own bitshift enums to allow qemugtk to know difference between left and right alt - something gtk doesnt provide in its modifiers mask. this uses qemu's own modifier_state[] map in order to guess correctly */
-typedef enum
-{
-       gtkshiftleft = 1 << 0,
-       gtkshiftright = 1 << 1,
-       gtkcontrolleft = 1 << 2,
-       gtkcontrolright = 1 << 3,
-       gtkaltleft = 1 << 4,
-       gtkaltright = 1 << 5,
-       gtkcapslock = 1 << 6
-} gtk2keymod;
-
-
-static GtkWidget *window, *swindow;
-static GtkWidget *event_port, *menubar;
-static GdkImage *image=NULL;
-static GdkCursor *invisible_cursor;
-static int ox = 0, oy = 0;
-static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
-static int gui_rgrab; /* if true, all keyboard/mouse events are grabbed */
-static int last_vm_running;
-static int gui_saved_grab;
-static int gui_fullscreen;
-static int gui_key_modifier_pressed;
-static int gui_keysym;
-static int gui_fullscreen_initial_grab;
-static int gui_grab_code = gtkaltleft | gtkcontrolleft;
-static uint8_t modifiers_state[256];
-static int window_resize = 0;
-static unsigned int cw, ch;
-static gint win_x, win_y, win_w, win_h;
-static GtkWidget * box; /* because GtkWindow/GtkBin holds only one widget */
-
-static gboolean gtk2_expose(GtkWidget *wid, GdkEventExpose *event)
-{
-    if (gui_fullscreen && wid == event_port) return FALSE;
-    if (!gui_fullscreen && wid == window) return FALSE;
-    gdk_draw_image(wid->window, wid->style->fg_gc[GTK_WIDGET_STATE(wid)], image, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height);
-    return TRUE;
-}
-
-static void gtk2_update(DisplayState *ds, int x, int y, int w, int h)
-{
-    //    printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
-    GdkEventExpose ev;
-    ev.area.x = x;
-    ev.area.y = y;
-    ev.area.width = w;
-    ev.area.height = h;
-    /* catch the first resize done by the init function - make sure we don't **
-    ** try to draw an image until screen has been finalized/realized/etc */
-    if (event_port->window != NULL)
-    {
-       if (gui_fullscreen)
-           gtk2_expose(window, &ev);
-       else
-           gtk2_expose(event_port, &ev);
-    }
-}
-
-static void gtk2_resize(DisplayState *ds, int w, int h)
-{
-
-    //    printf(" resizing to %d %d\n", w, h);
-
-    if (gui_fullscreen)
-    {
-       if (cw != w || ch != h)
-       {
-           fullscreen_switch(win_x, win_y, w, h); /* changing video modes */
-/* apparently GTK enjoys moving static windows all over the place while
-they are being resized - so we have to be tricky */
-           //gtk_window_move(GTK_WINDOW(window), win_x, win_y);
-           //gtk_window_move(GTK_WINDOW(window), 0, 0);
-           gdk_window_move_resize(window->window, 0, 0, w, h);
-       }
-    }
-
-    cw = w; ch = h;
-
-    if (image)
-        g_object_unref(image);
-
-/* gdk_visual_get_best_with_depth() ??? but then how to paint onto window? */
-    image = gdk_image_new(GDK_IMAGE_NORMAL, gdk_visual_get_system(), w, h);
-    gdk_image_set_colormap(image, gdk_colormap_get_system());
-
-    gtk_widget_set_size_request(event_port, w, h);
-    if (window_resize && (window->window != NULL))
-       gdk_window_move_resize(window->window, win_x, win_y, w+25, h+50);
-
-    ds->data = image->mem;
-    ds->linesize = image->bpl;
-    ds->depth = image->bits_per_pixel;
-    ds->width = w;
-    ds->height = h;
-    gtk2_update(ds, 0, 0, w, h);
-}
-
-static gboolean gtk2_config(GtkWidget *wid, GdkEventConfigure *ev, DisplayState *ds)
-{
-    if (!gui_fullscreen)
-    {
-       win_x = ev->x;
-       win_y = ev->y;
-       win_w = ev->width;
-       win_h = ev->height;
-    }
-    return FALSE;
-}
-
-/* generic keyboard conversion */
-
-#include "gdk_keysym.h"
-#include "keymaps.c"
-
-static kbd_layout_t *kbd_layout = NULL;
-
-static uint8_t gtk2_keyevent_to_keycode_generic(const GdkEventKey *ev)
-{
-    int keysym;
-    /* workaround for X11+SDL bug with AltGR - is it still needed for Gtk2? */
-    keysym = ev->keyval;
-    if (keysym == 0 && ev->hardware_keycode == 113)
-       keysym = GDK_Mode_switch;
-    return keysym2scancode(kbd_layout, keysym);
-}
-
-/* specific keyboard conversions from scan codes */
-
-#if defined(_WIN32)
-
-#include <windows.h>
-
-static UINT vk2scan(UINT vk)
-{
-       return MapVirtualKey(vk,0);
-}
-static uint8_t gtk2_keyevent_to_keycode(const GdkEventKey *ev)
-{   
-    return (uint8_t)vk2scan((UINT)(ev->hardware_keycode));
-}
-
-#else
-
-static const uint8_t x_keycode_to_pc_keycode[61] = {
-   0xc7,      /*  97  Home   */
-   0xc8,      /*  98  Up     */
-   0xc9,      /*  99  PgUp   */
-   0xcb,      /* 100  Left   */
-   0x4c,        /* 101  KP-5   */
-   0xcd,      /* 102  Right  */
-   0xcf,      /* 103  End    */
-   0xd0,      /* 104  Down   */
-   0xd1,      /* 105  PgDn   */
-   0xd2,      /* 106  Ins    */
-   0xd3,      /* 107  Del    */
-   0x9c,      /* 108  Enter  */
-   0x9d,      /* 109  Ctrl-R */
-   0x0,       /* 110  Pause  */
-   0xb7,      /* 111  Print  */
-   0xb5,      /* 112  Divide */
-   0xb8,      /* 113  Alt-R  */
-   0xc6,      /* 114  Break  */   
-   0xdb,         /* 115 windows left button */
-   0xdc,         /* 116 windows right button */
-   0xdd,         /* 117 right menu button */
-   0x0,         /* 118 */
-   0x0,         /* 119 */
-   0x70,         /* 120 Hiragana_Katakana */
-   0x0,         /* 121 */
-   0x0,         /* 122 */
-   0x73,         /* 123 backslash */
-   0x0,         /* 124 */
-   0x0,         /* 125 */
-   0x0,         /* 126 */
-   0x0,         /* 127 */
-   0x0,         /* 128 */
-   0x79,         /* 129 Henkan */
-   0x0,         /* 130 */
-   0x7b,         /* 131 Muhenkan */
-   0x0,         /* 132 */
-   0x7d,         /* 133 Yen */
-   0x0,         /* 134 */
-   0x0,         /* 135 */
-   0x47,         /* 136 KP_7 */
-   0x48,         /* 137 KP_8 */
-   0x49,         /* 138 KP_9 */
-   0x4b,         /* 139 KP_4 */
-   0x4c,         /* 140 KP_5 */
-   0x4d,         /* 141 KP_6 */
-   0x4f,         /* 142 KP_1 */
-   0x50,         /* 143 KP_2 */
-   0x51,         /* 144 KP_3 */
-   0x52,         /* 145 KP_0 */
-   0x53,         /* 146 KP_. */
-   0x47,         /* 147 KP_HOME */
-   0x48,         /* 148 KP_UP */
-   0x49,         /* 149 KP_PgUp */
-   0x4b,         /* 150 KP_Left */
-   0x4c,         /* 151 KP_ */
-   0x4d,         /* 152 KP_Right */
-   0x4f,         /* 153 KP_End */
-   0x50,         /* 154 KP_Down */
-   0x51,         /* 155 KP_PgDn */
-   0x52,         /* 156 KP_Ins */
-   0x53,         /* 157 KP_Del */
-};
-
-static uint8_t gtk2_keyevent_to_keycode(const GdkEventKey *ev)
-{
-    int keycode;
-
-    keycode = ev->hardware_keycode;
-
-    if (keycode < 9) {
-       keycode = 0;
-    } else if (keycode < 97) {
-       keycode -= 8; /* just an offset */
-    } else if (keycode < 158) {
-       /* use conversion table */
-       keycode = x_keycode_to_pc_keycode[keycode - 97];
-    } else {
-       keycode = 0;
-    }
-    return keycode;
-}
-
-#endif
-
-static void reset_keys(void)
-{
-    int i;
-    for(i = 0; i < 256; i++) {
-       if (modifiers_state[i]) {
-           if (i & 0x80)
-               kbd_put_keycode(0xe0);
-           kbd_put_keycode(i | 0x80);
-           modifiers_state[i] = 0;
-       }
-    }
-}
-
-/* convert GDK modifiers and invoke ugly hack to distinguish
-between left and right shift/control/alt */
-static guint gtk2_GetModState(const GdkEventKey *ev)
-{
-       guint key = 0, keyval = ev->keyval, state = ev->state;
-       switch(keyval)
-       {
-               case GDK_Shift_L:
-                       if (ev->type != GDK_KEY_RELEASE)
-                               key |= gtkshiftleft;
-                       keyval = 1;
-                       break;
-               case GDK_Shift_R:
-                       if (ev->type != GDK_KEY_RELEASE)
-                               key |= gtkshiftright;
-                       keyval = 1;
-                       break;
-               case GDK_Control_L:
-                       if (ev->type != GDK_KEY_RELEASE)
-                               key |= gtkcontrolleft;
-                       keyval = 2;
-                       break;
-               case GDK_Control_R:
-                       if (ev->type != GDK_KEY_RELEASE)
-                               key |= gtkcontrolright;
-                       keyval = 2;
-                       break;
-               case GDK_Alt_L:
-                       if (ev->type != GDK_KEY_RELEASE)
-                               key |= gtkaltleft;
-                       keyval = 3;
-                       break;
-               case GDK_Alt_R:
-                       if (ev->type != GDK_KEY_RELEASE)
-                               key |= gtkaltright;
-                       keyval = 3;
-                       break;
-               case GDK_Caps_Lock:
-                       if (ev->type != GDK_KEY_RELEASE)
-                               key |= gtkcapslock;
-                       keyval = 4;
-                       break;
-               default:
-                       keyval = 0;
-                       break;
-       }
-       if (keyval != 1 && (state & GDK_SHIFT_MASK))
-       {
-               if (modifiers_state[0x2a])
-                       key |= gtkshiftleft;
-               if (modifiers_state[0x36])
-                       key |= gtkshiftright;
-       }
-       if (keyval != 2 && (state & GDK_CONTROL_MASK))
-       {
-               if (modifiers_state[0x1d])
-                       key |= gtkcontrolleft;
-               if (modifiers_state[0x9d])
-                       key |= gtkcontrolright;
-       }
-       if (keyval != 3 && (state & GDK_MOD1_MASK)) /* fixme: need to do a check to make sure that alt is mapped to GDK_MOD1_MASK in the GDK_Keymap */
-       {
-               if (modifiers_state[0x38])
-                       key |= gtkaltleft;
-               if (modifiers_state[0xb8])
-                       key |= gtkaltright;
-       }
-       if (keyval != 4 && (state & GDK_LOCK_MASK))
-               key |= gtkcapslock;
-       return key;
-}
-
-static void gtk2_process_key(GdkEventKey *ev)
-{
-    int keycode, v;
-
-    if (ev->keyval == GDK_Pause) {
-       /* specific case */
-       v = 0;
-       if (ev->type == GDK_KEY_RELEASE)
-           v |= 0x80;
-       kbd_put_keycode(0xe1);
-       kbd_put_keycode(0x1d | v);
-       kbd_put_keycode(0x45 | v);
-       return;
-    }
-
-    if (kbd_layout) {
-       keycode = gtk2_keyevent_to_keycode_generic(ev);
-    } else {
-       keycode = gtk2_keyevent_to_keycode(ev);
-    }
-
-    switch(keycode) {
-    case 0x00:
-       /* sent when leaving window: reset the modifiers state */
-       reset_keys();
-       return;
-    case 0x2a:                          /* Left Shift */
-    case 0x36:                          /* Right Shift */
-    case 0x1d:                          /* Left CTRL */
-    case 0x9d:                          /* Right CTRL */
-    case 0x38:                          /* Left ALT */
-    case 0xb8:                         /* Right ALT */
-       if (ev->type == GDK_KEY_RELEASE)
-           modifiers_state[keycode] = 0;
-       else
-           modifiers_state[keycode] = 1;
-       break;
-    case 0x45: /* num lock */
-    case 0x3a: /* caps lock */
-       /* GTK does send the key up event, so we dont generate it */
-       /*kbd_put_keycode(keycode);
-       kbd_put_keycode(keycode | 0x80);
-       return;*/
-       break;
-    }
-
-    /* now send the key code */
-    if (keycode & 0x80)
-       kbd_put_keycode(0xe0);
-    if (ev->type == GDK_KEY_RELEASE)
-       kbd_put_keycode(keycode | 0x80);
-    else
-       kbd_put_keycode(keycode & 0x7f);
-}
-
-static void gtk2_update_caption(void)
-{
-    char buf[1024];
-    strcpy(buf, "QEMU Gtk");
-    if (!vm_running) {
-       strcat(buf, " [Stopped]");
-    }
-    if (gui_grab) {
-       strcat(buf, " - Press Ctrl-Alt to exit grab");
-    }
-    gtk_window_set_title(GTK_WINDOW(window), buf);
-}
-
-/* what a nasty hack. this should be a part of the GDK, not external!!! */
-#include "gdk_set_window_pointer.c"
-
-static void gtk2_grab_start(void)
-{
-    gint y;
-    guint events;
-    GdkModifierType state; /* dummy var */
-    GtkWidget * grab;
-    if (gui_fullscreen) /* make sure grab is on correct x window */
-       grab = window;
-    else
-       grab = event_port;
-if (gui_rgrab || gui_fullscreen)
-{
-    events = GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_SCROLL_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK;
-    y = gdk_pointer_grab(grab->window, TRUE, events, grab->window, invisible_cursor, GDK_CURRENT_TIME);
-    if (y)
-       printf("GTK Warning - pointer grab failed!\n");
-    y = gdk_keyboard_grab(grab->window, TRUE, GDK_CURRENT_TIME);
-    if (y)
-       printf("GTK Warning - keyboard grab failed!\n");
-}
-    /* do a dummy read to avoid moving mouse - set ox and oy to stay in sync */
-    gdk_window_get_pointer(event_port->window, &ox, &oy, &state);
-    gui_grab = 1;
-    gtk2_update_caption();
-}
-
-static void gtk2_grab_end(void)
-{
-    GtkWidget * grab;
-    if (gui_fullscreen)
-       grab = window;
-    else
-       grab = event_port;
-if (gui_rgrab || gui_fullscreen)
-{
-    gdk_pointer_ungrab(GDK_CURRENT_TIME);
-    gdk_keyboard_ungrab(GDK_CURRENT_TIME);
-    gdk_window_set_pointer(grab->window, win_x, win_y);
-}
-    gui_grab = 0;
-    gtk2_update_caption();
-}
-
-static gboolean gtk2_send_mouse_event(GtkWidget *wid, GdkEvent *ev)
-{
-    int x, y, dx, dy, dz, state, buttons;
-    GtkWidget * grab;
-    if (gui_fullscreen) /* make sure grab is on correct x window */
-       grab = window;
-    else
-       grab = event_port;
-
-    if (gui_fullscreen && wid == event_port) return FALSE;
-    if (!gui_fullscreen && wid == window) return FALSE;
-    if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS)
-       return TRUE; /* double or triple click - superflurious - ignore */
-
-    if (gui_grab)
-    {
-
-    if (ev->type == GDK_MOTION_NOTIFY && ev->motion.is_hint)
-    {
-       gdk_window_get_pointer(ev->motion.window, &x, &y, (GdkModifierType*)&state);
-    }
-    else
-    {
-       x = ev->motion.x;
-       y = ev->motion.y;
-       /* scroll.state occupies a different position in the union */
-       if (ev->type == GDK_SCROLL)
-       state = ev->scroll.state;
-       else
-       state = ev->motion.state;
-    }
-
-    dx = x - ox;
-    dy = y - oy;
-    // prevent infinite looping - 2.6.X
-    if ((ev->type == GDK_MOTION_NOTIFY) && (dx == 0) && (dy == 0)) return TRUE;
-    dz = 0;
-    ox = x;
-    oy = y;
-
-    buttons = 0;
-    if ((state & GDK_BUTTON1_MASK))
-       buttons |= MOUSE_EVENT_LBUTTON;
-    if ((state & GDK_BUTTON3_MASK))
-       buttons |= MOUSE_EVENT_RBUTTON;
-    if ((state & GDK_BUTTON2_MASK))
-       buttons |= MOUSE_EVENT_MBUTTON;
-
-    if (ev->type == GDK_BUTTON_PRESS)
-    {
-       if (ev->button.button == 1)
-           buttons |= MOUSE_EVENT_LBUTTON;
-       if (ev->button.button == 3)
-           buttons |= MOUSE_EVENT_RBUTTON;
-       if (ev->button.button == 2)
-           buttons |= MOUSE_EVENT_MBUTTON;
-    }
-    else if (ev->type == GDK_BUTTON_RELEASE)
-    {
-    /* not sure if this is really necessary, but just to be on the safe side **
-    ** reset qemu's mask so that a button thats being released will be shown **
-    * missing from the mask (which lets the guest know the button was relased */
-       buttons = 0;
-
-       if ((state & GDK_BUTTON1_MASK) && ev->button.button != 1)
-           buttons |= MOUSE_EVENT_LBUTTON;
-       if ((state & GDK_BUTTON3_MASK) && ev->button.button != 3)
-           buttons |= MOUSE_EVENT_RBUTTON;
-       if ((state & GDK_BUTTON2_MASK) && ev->button.button != 2)
-           buttons |= MOUSE_EVENT_MBUTTON;
-    }
-    else if (ev->type == GDK_SCROLL)
-    {
-       /* test wheel - copied from Sebastien Bechet's gtk.c */
-       if (ev->scroll.direction == GDK_SCROLL_UP)
-           dz--;
-       if (ev->scroll.direction == GDK_SCROLL_DOWN)
-           dz++;
-    }
-
-    if ((ev->type == GDK_MOTION_NOTIFY) && (gui_rgrab || gui_fullscreen))
-    {
-       /* wrap the x,y coordinates back onto the window */
-       if (ev->motion.x <= (cw/4))
-           x = ((3*cw/4)-1);
-       if (ev->motion.y <= (ch/4))
-           y = ((3*ch/4)-1);
-       if (ev->motion.x >= (3*cw/4))
-           x = (cw/4)+1;
-       if (ev->motion.y >= (3*ch/4))
-           y = (ch/4)+1;
-
-       /* make internal mouse move invisible */
-       ox = x;
-       oy = y;
-
-       gdk_window_set_pointer(grab->window, (gint)x, (gint)y);
-    }
-
-    kbd_mouse_event(dx, dy, dz, buttons);
-
-    }
-    else
-    {
-
-    if (ev->type == GDK_BUTTON_PRESS && ev->button.button == 1)
-    {
-       /* start grabbing all events */
-       gtk2_grab_start();
-    }
-
-    }
-    return TRUE;
-}
-
-static void toggle_full_screen(DisplayState *ds)
-{
-    gui_fullscreen = !gui_fullscreen;
-    gtk2_resize(ds, image->width, image->height);
-    if (gui_fullscreen) {
-       gui_saved_grab = gui_grab;
-       gtk2_grab_start();
-       gtk_window_get_position(GTK_WINDOW(window), &win_x, &win_y);
-       gdk_window_move_resize(window->window, 0, 0, ds->width, ds->height);
-       gtk_widget_hide(box);
-       fullscreen_switch(win_x, win_y, ds->width, ds->height);
-    } else {
-       fullscreen_reset();
-       gdk_window_move_resize(window->window, win_x, win_y, win_w, win_h);
-       gui_fullscreen = !gui_fullscreen;
-       if (!gui_saved_grab)
-           gtk2_grab_end();
-       gui_fullscreen = !gui_fullscreen;
-       gtk_widget_show(box);
-    }
-    vga_invalidate_display();
-    vga_update_display();
-}
-
-static gboolean gtk2_key_press(GtkWidget *wid, GdkEventKey *ev, DisplayState *ds)
-{
-       int mod_state, internal_key = 0;
-           if (ev->type == GDK_KEY_PRESS) {
-               mod_state = (gtk2_GetModState(ev) & (int)gui_grab_code) == (int)gui_grab_code;
-               gui_key_modifier_pressed = mod_state;
-               if (gui_key_modifier_pressed) {
-                   int keycode;
-                   internal_key = 1;
-                   keycode = gtk2_keyevent_to_keycode(ev);
-                   switch(keycode) {
-                   case 0x21: /* 'f' key on US keyboard */
-                       toggle_full_screen(ds);
-                       gui_keysym = 1;
-                       break;
-                   case 0x02 ... 0x0a: /* '1' to '9' keys */ 
-                       console_select(keycode - 0x02);
-                       if (is_active_console(vga_console)) {
-                           /* tell the vga console to redisplay itself */
-                           vga_invalidate_display();
-                       } else {
-                           /* display grab if going to a text console */
-                           if (gui_grab)
-                               gtk2_grab_end();
-                       }
-                       gui_keysym = 1;
-                       break;
-                   default:
-                       break;
-                   }
-               } else if (!is_active_console(vga_console)) {
-                   int keysym;
-                   keysym = 0;
-                   if (ev->state & GDK_CONTROL_MASK) {
-                       switch(ev->keyval) {
-                       case GDK_Up: keysym = QEMU_KEY_CTRL_UP; break;
-                       case GDK_Down: keysym = QEMU_KEY_CTRL_DOWN; break;
-                       case GDK_Left: keysym = QEMU_KEY_CTRL_LEFT; break;
-                       case GDK_Right: keysym = QEMU_KEY_CTRL_RIGHT; break;
-                       case GDK_Home: keysym = QEMU_KEY_CTRL_HOME; break;
-                       case GDK_End: keysym = QEMU_KEY_CTRL_END; break;
-                       case GDK_Page_Up: keysym = QEMU_KEY_CTRL_PAGEUP; break;
-                       case GDK_Page_Down: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
-                       default: break;
-                       }
-                   } else {
-                       switch(ev->keyval) {
-                       case GDK_Up: keysym = QEMU_KEY_UP; break;
-                       case GDK_Down: keysym = QEMU_KEY_DOWN; break;
-                       case GDK_Left: keysym = QEMU_KEY_LEFT; break;
-                       case GDK_Right: keysym = QEMU_KEY_RIGHT; break;
-                       case GDK_Home: keysym = QEMU_KEY_HOME; break;
-                       case GDK_End: keysym = QEMU_KEY_END; break;
-                       case GDK_Page_Up: keysym = QEMU_KEY_PAGEUP; break;
-                       case GDK_Page_Down: keysym = QEMU_KEY_PAGEDOWN; break;
-                       case GDK_BackSpace: keysym = QEMU_KEY_BACKSPACE; break;
-                       case GDK_Delete: keysym = QEMU_KEY_DELETE; break;
-                       default: break;
-                       }
-                   }
-                   if (keysym) {
-                       kbd_put_keysym(keysym);
-                   } /*else if (ev->key.keysym.unicode != 0) {
-                       kbd_put_keysym(ev->key.keysym.unicode);
-                   }*/
-               }
-           } else if (ev->type == GDK_KEY_RELEASE) {
-               mod_state = (gtk2_GetModState(ev) & gui_grab_code);
-               if (!mod_state) {
-                   if (gui_key_modifier_pressed) {
-                       if (gui_keysym == 0) {
-                           /* exit/enter grab if pressing Ctrl-Alt */
-                           if (!gui_grab)
-                               gtk2_grab_start();
-                           else
-                               gtk2_grab_end();
-                           /* SDL does not send back all the
-                              modifiers key, so we must correct it */
-                           reset_keys();
-                           return TRUE;
-                       }
-                       gui_key_modifier_pressed = 0;
-                       gui_keysym = 0;
-                       internal_key = 1;
-                   }
-               }
-           }
-           if (is_active_console(vga_console) && !internal_key) 
-               gtk2_process_key(ev);
-           else if (internal_key && ev->type == GDK_KEY_RELEASE)
-           {
-               modifiers_state[0x38] = 0;
-               modifiers_state[0x1d] = 0;
-               kbd_put_keycode(0x38 | 0x80);
-               kbd_put_keycode(0x1d | 0x80);
-           }
-           else if (internal_key && ev->type == GDK_KEY_PRESS)
-           {
-               modifiers_state[0x38] = 1;
-               modifiers_state[0x1d] = 1;
-           }
-       return TRUE;
-}
-
-static void gtk2_refresh(DisplayState *ds)
-{
-    if (last_vm_running != vm_running) {
-       last_vm_running = vm_running;
-       gtk2_update_caption();
-    }
-    if (ds->data != image->mem)
-    {
-       ds->data = image->mem;
-    }
-
-    if (is_active_console(vga_console))                                         
-       vga_update_display();                                                   
-    while (gtk_events_pending())
-       gtk_main_iteration();
-}
-
-static void gtk2_cleanup(void) 
-{
-    if (gtk_main_level() != 0)
-       gtk_main_quit();
-    fullscreen_cleanup();
-}
-
-static gboolean gtk2_deletewin(void)
-{
-    /* signal qemu that its time to shut itself off - this is the place that we hook to trap attempts to close the main qemu window */
-    qemu_system_shutdown_request();
-    return FALSE;
-    return TRUE; /* dont close the window right away! give qemu time to think */
-}
-
-static void gtk2_destroy(void)
-{
-    /* ideally we would call a hook here so qemu could clean itself up */
-    gtk2_cleanup();
-}
-
-static int gargc=0;
-static char ** gargv=NULL;
-void gtk2_display_init(DisplayState *ds, int full_screen)
-{
-    int events;
-
-#if defined(__APPLE__)
-    /* always use generic keymaps */
-    if (!keyboard_layout)
-       keyboard_layout = "en-us";
-#endif
-    if(keyboard_layout) {
-       kbd_layout = init_keyboard_layout(keyboard_layout);
-       if (!kbd_layout)
-           exit(1);
-    }
-
-/* note - this strips the GTK-specific args after the main program is done with them */
-    if (!gtk_init_check (&gargc,&gargv))
-    {
-       fprintf(stderr, "Could not load GTK\n");
-       exit(0);
-    }
-    gui_rgrab = 0;
-    fullscreen_init();
-
-/* note: adding GDK_DRAG_* and GDK_DROP_* would provide a mechanism for supporting drag and drop between host and guest */
-    events = GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK | GDK_SCROLL_MASK | GDK_STRUCTURE_MASK;
-
-    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    swindow = gtk_scrolled_window_new(NULL,NULL);
-    event_port = gtk_event_box_new();
-    menubar = gtk_menu_bar_new();
-    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow), GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
-    box = gtk_vbox_new(FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(window), box);
-    create_winmain(window, box, swindow);
-    gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(swindow), event_port);
-    gtk_widget_set_events(event_port, events);
-    gtk_window_set_default_size(GTK_WINDOW(window), 720, 420);
-    gtk_widget_set_size_request(window, 0, 0);
-    gtk_widget_set_size_request(swindow, 720, 400);
-    gtk_widget_set_size_request(event_port, 720, 400);
-    gtk_window_set_gravity(GTK_WINDOW(window), GDK_GRAVITY_STATIC);
-
-    g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(gtk2_deletewin), NULL);
-    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk2_destroy), NULL);
-    gtk_container_set_border_width(GTK_CONTAINER(window), 0);
-
-    g_signal_connect(G_OBJECT(window), "configure_event", G_CALLBACK(gtk2_config), NULL);
-    g_signal_connect(G_OBJECT(window), "expose_event", G_CALLBACK(gtk2_expose), NULL);
-    g_signal_connect(G_OBJECT(window), "motion_notify_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(window), "button_press_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(window), "button_release_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(window), "scroll_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(event_port), "expose_event", G_CALLBACK(gtk2_expose), NULL);
-    g_signal_connect(G_OBJECT(event_port), "motion_notify_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(event_port), "button_press_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(event_port), "button_release_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(event_port), "scroll_event", G_CALLBACK(gtk2_send_mouse_event), NULL);
-    g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(gtk2_key_press), ds);
-    g_signal_connect(G_OBJECT(window), "key_release_event", G_CALLBACK(gtk2_key_press), ds);
-
-    ds->dpy_update = gtk2_update;
-    ds->dpy_resize = gtk2_resize;
-    ds->dpy_refresh = gtk2_refresh;
-
-    gchar nullpixdata[1] = { 0 };
-    GdkColor nullcolor = { 0, 0, 0, 0 };
-    GdkPixmap *invis = gdk_bitmap_create_from_data(window->window, nullpixdata, 1, 1);
-    invisible_cursor = gdk_cursor_new_from_pixmap(invis, invis, &nullcolor, &nullcolor, 0, 0);
-
-    gtk2_resize(ds, 720, 400);
-    gtk2_update_caption();
-    gui_grab = 0;
-
-    gtk_widget_show(event_port);
-    gtk_widget_show(swindow);
-    gtk_widget_show(box);
-    gtk_widget_show(window);
-    if (full_screen) {
-       gui_fullscreen = 1;
-       gui_fullscreen_initial_grab = 1;
-       gtk2_grab_start();
-    }
-}
-
-/* we are allowed to look at the args, but not allowed to modify them
-with the exception that we have to remove args that are meant for us, as
-main qemu will not recognize them */
-void gui_checkargs(int * pargc, char *** pargv)
-{
-    int argc = *pargc;
-    char ** argv = *pargv;
-    char ** vargv;
-    int i, j = 0;
-    vargv = malloc(argc * sizeof(char*));
-    for (i = 0; i < argc; i++)
-    {
-       if (!strcmp(argv[i], "-window-resize-on"))
-       {
-               window_resize = 1;
-               (*pargc)--;
-       }
-       else if (!strcmp(argv[i], "-raw-grab"))
-       {
-               gui_rgrab = 1;
-               (*pargc)--;
-       }
-       else
-       {
-               vargv[j] = argv[i];
-               j++;
-       }
-    }
-    /* so lets hide them */
-    for (i = 0; i < *pargc; i++)
-    {
-       (*pargv)[i] = vargv[i];
-    }
-    if (argc != (*pargc)) (*pargv)[*pargc] = NULL;
-    free(vargv);
-    /* save a copy so we can pass them to gtk_init() later */
-    gargc = *pargc;
-    gargv = *pargv;
-}
-
diff --git a/qemu-gtk/interface.c b/qemu-gtk/interface.c
deleted file mode 100644 (file)
index d71b48c..0000000
+++ /dev/null
@@ -1,1172 +0,0 @@
-/*
- * DO NOT EDIT THIS FILE - it is generated by Glade.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtk.h>
-
-#include "callbacks.h"
-#include "interface.h"
-#include "support.h"
-
-#define GLADE_HOOKUP_OBJECT(component,widget,name) \
-  g_object_set_data_full (G_OBJECT (component), name, \
-    gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
-
-#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
-  g_object_set_data (G_OBJECT (component), name, widget)
-
-GtkWidget*
-create_filechoosernew (void)
-{
-  GtkWidget *filechoosernew;
-  GtkWidget *dialog_vbox1;
-  GtkWidget *dialog_action_area1;
-  GtkWidget *button1;
-  GtkWidget *button2;
-
-  filechoosernew = gtk_file_chooser_dialog_new (_("Open File"), NULL, GTK_FILE_CHOOSER_ACTION_OPEN, NULL);
-  gtk_window_set_destroy_with_parent (GTK_WINDOW (filechoosernew), TRUE);
-  gtk_window_set_type_hint (GTK_WINDOW (filechoosernew), GDK_WINDOW_TYPE_HINT_DIALOG);
-
-  dialog_vbox1 = GTK_DIALOG (filechoosernew)->vbox;
-  gtk_widget_show (dialog_vbox1);
-
-  dialog_action_area1 = GTK_DIALOG (filechoosernew)->action_area;
-  gtk_widget_show (dialog_action_area1);
-  gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END);
-
-  button1 = gtk_button_new_from_stock ("gtk-cancel");
-  gtk_widget_show (button1);
-  gtk_dialog_add_action_widget (GTK_DIALOG (filechoosernew), button1, GTK_RESPONSE_CANCEL);
-  GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT);
-
-  button2 = gtk_button_new_from_stock ("gtk-open");
-  gtk_widget_show (button2);
-  gtk_dialog_add_action_widget (GTK_DIALOG (filechoosernew), button2, GTK_RESPONSE_OK);
-  GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT);
-
-  /* Store pointers to all widgets, for use by lookup_widget(). */
-  GLADE_HOOKUP_OBJECT_NO_REF (filechoosernew, filechoosernew, "filechoosernew");
-  GLADE_HOOKUP_OBJECT_NO_REF (filechoosernew, dialog_vbox1, "dialog_vbox1");
-  GLADE_HOOKUP_OBJECT_NO_REF (filechoosernew, dialog_action_area1, "dialog_action_area1");
-  GLADE_HOOKUP_OBJECT (filechoosernew, button1, "button1");
-  GLADE_HOOKUP_OBJECT (filechoosernew, button2, "button2");
-
-  gtk_widget_grab_default (button2);
-  return filechoosernew;
-}
-
-GtkWidget*
-create_filechooseropen (void)
-{
-  GtkWidget *filechooseropen;
-  GtkWidget *dialog_vbox2;
-  GtkWidget *dialog_action_area2;
-  GtkWidget *button3;
-  GtkWidget *button4;
-
-  filechooseropen = gtk_file_chooser_dialog_new (_("Open File"), NULL, GTK_FILE_CHOOSER_ACTION_OPEN, NULL);
-  gtk_window_set_type_hint (GTK_WINDOW (filechooseropen), GDK_WINDOW_TYPE_HINT_DIALOG);
-
-  dialog_vbox2 = GTK_DIALOG (filechooseropen)->vbox;
-  gtk_widget_show (dialog_vbox2);
-
-  dialog_action_area2 = GTK_DIALOG (filechooseropen)->action_area;
-  gtk_widget_show (dialog_action_area2);
-  gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area2), GTK_BUTTONBOX_END);
-
-  button3 = gtk_button_new_from_stock ("gtk-cancel");
-  gtk_widget_show (button3);
-  gtk_dialog_add_action_widget (GTK_DIALOG (filechooseropen), button3, GTK_RESPONSE_CANCEL);
-  GTK_WIDGET_SET_FLAGS (button3, GTK_CAN_DEFAULT);
-
-  button4 = gtk_button_new_from_stock ("gtk-open");
-  gtk_widget_show (button4);
-  gtk_dialog_add_action_widget (GTK_DIALOG (filechooseropen), button4, GTK_RESPONSE_OK);
-  GTK_WIDGET_SET_FLAGS (button4, GTK_CAN_DEFAULT);
-
-  /* Store pointers to all widgets, for use by lookup_widget(). */
-  GLADE_HOOKUP_OBJECT_NO_REF (filechooseropen, filechooseropen, "filechooseropen");
-  GLADE_HOOKUP_OBJECT_NO_REF (filechooseropen, dialog_vbox2, "dialog_vbox2");
-  GLADE_HOOKUP_OBJECT_NO_REF (filechooseropen, dialog_action_area2, "dialog_action_area2");
-  GLADE_HOOKUP_OBJECT (filechooseropen, button3, "button3");
-  GLADE_HOOKUP_OBJECT (filechooseropen, button4, "button4");
-
-  gtk_widget_grab_default (button4);
-  return filechooseropen;
-}
-
-GtkWidget*
-create_filechoosersave (void)
-{
-  GtkWidget *filechoosersave;
-  GtkWidget *dialog_vbox3;
-  GtkWidget *dialog_action_area3;
-  GtkWidget *button5;
-  GtkWidget *button6;
-
-  filechoosersave = gtk_file_chooser_dialog_new (_("Save File As"), NULL, GTK_FILE_CHOOSER_ACTION_OPEN, NULL);
-  gtk_window_set_type_hint (GTK_WINDOW (filechoosersave), GDK_WINDOW_TYPE_HINT_DIALOG);
-
-  dialog_vbox3 = GTK_DIALOG (filechoosersave)->vbox;
-  gtk_widget_show (dialog_vbox3);
-
-  dialog_action_area3 = GTK_DIALOG (filechoosersave)->action_area;
-  gtk_widget_show (dialog_action_area3);
-  gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area3), GTK_BUTTONBOX_END);
-
-  button5 = gtk_button_new_from_stock ("gtk-cancel");
-  gtk_widget_show (button5);
-  gtk_dialog_add_action_widget (GTK_DIALOG (filechoosersave), button5, GTK_RESPONSE_CANCEL);
-  GTK_WIDGET_SET_FLAGS (button5, GTK_CAN_DEFAULT);
-
-  button6 = gtk_button_new_from_stock ("gtk-open");
-  gtk_widget_show (button6);
-  gtk_dialog_add_action_widget (GTK_DIALOG (filechoosersave), button6, GTK_RESPONSE_OK);
-  GTK_WIDGET_SET_FLAGS (button6, GTK_CAN_DEFAULT);
-
-  /* Store pointers to all widgets, for use by lookup_widget(). */
-  GLADE_HOOKUP_OBJECT_NO_REF (filechoosersave, filechoosersave, "filechoosersave");
-  GLADE_HOOKUP_OBJECT_NO_REF (filechoosersave, dialog_vbox3, "dialog_vbox3");
-  GLADE_HOOKUP_OBJECT_NO_REF (filechoosersave, dialog_action_area3, "dialog_action_area3");
-  GLADE_HOOKUP_OBJECT (filechoosersave, button5, "button5");
-  GLADE_HOOKUP_OBJECT (filechoosersave, button6, "button6");
-
-  gtk_widget_grab_default (button6);
-  return filechoosersave;
-}
-
-GtkWidget*
-create_winprefs (void)
-{
-  GtkWidget *winprefs3;
-  GtkWidget *vbox10;
-  GtkWidget *notebook3;
-  GtkWidget *vbox11;
-  GtkWidget *hbox33;
-  GtkWidget *label86;
-  GtkWidget *entry58;
-  GtkWidget *label87;
-  GtkWidget *hbox34;
-  GtkWidget *label88;
-  GtkWidget *combobox7;
-  GtkWidget *frame7;
-  GtkWidget *alignment7;
-  GtkWidget *vbox12;
-  GtkWidget *table13;
-  GtkWidget *entry59;
-  GtkWidget *entry60;
-  GtkWidget *entry61;
-  GtkWidget *entry62;
-  GtkWidget *button57;
-  GtkWidget *button58;
-  GtkWidget *button59;
-  GtkWidget *button60;
-  GtkWidget *button61;
-  GtkWidget *button62;
-  GtkWidget *entry63;
-  GtkWidget *entry64;
-  GtkWidget *checkbutton12;
-  GtkWidget *checkbutton13;
-  GtkWidget *checkbutton14;
-  GtkWidget *checkbutton15;
-  GtkWidget *checkbutton16;
-  GtkWidget *checkbutton17;
-  GtkWidget *hseparator2;
-  GtkWidget *checkbutton18;
-  GtkWidget *label89;
-  GtkWidget *label74;
-  GtkWidget *frame8;
-  GtkWidget *alignment8;
-  GtkWidget *vbox13;
-  GtkWidget *table14;
-  GtkWidget *entry65;
-  GtkWidget *entry66;
-  GtkWidget *entry67;
-  GtkWidget *button63;
-  GtkWidget *button64;
-  GtkWidget *label93;
-  GtkWidget *label92;
-  GtkWidget *label91;
-  GtkWidget *label90;
-  GtkWidget *frame9;
-  GtkWidget *alignment9;
-  GtkWidget *table15;
-  GtkWidget *hbox35;
-  GtkWidget *combobox8;
-  GtkWidget *entry68;
-  GtkWidget *label94;
-  GtkWidget *entry69;
-  GtkWidget *label95;
-  GtkWidget *button65;
-  GtkWidget *hbox36;
-  GtkWidget *combobox9;
-  GtkWidget *button66;
-  GtkWidget *label96;
-  GtkWidget *checkbutton19;
-  GtkWidget *label81;
-  GtkWidget *table16;
-  GtkWidget *label97;
-  GtkWidget *label98;
-  GtkWidget *label99;
-  GtkWidget *entry72;
-  GtkWidget *entry70;
-  GtkWidget *entry71;
-  GtkWidget *label85;
-  GtkWidget *hbuttonbox3;
-  GtkWidget *button55;
-  GtkWidget *button56;
-  GtkTooltips *tooltips;
-
-  tooltips = gtk_tooltips_new ();
-
-  winprefs3 = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-  gtk_window_set_title (GTK_WINDOW (winprefs3), _("Preferences"));
-
-  vbox10 = gtk_vbox_new (FALSE, 0);
-  gtk_widget_show (vbox10);
-  gtk_container_add (GTK_CONTAINER (winprefs3), vbox10);
-
-  notebook3 = gtk_notebook_new ();
-  gtk_widget_show (notebook3);
-  gtk_box_pack_start (GTK_BOX (vbox10), notebook3, TRUE, TRUE, 0);
-  gtk_notebook_set_scrollable (GTK_NOTEBOOK (notebook3), TRUE);
-
-  vbox11 = gtk_vbox_new (FALSE, 0);
-  gtk_widget_show (vbox11);
-  gtk_container_add (GTK_CONTAINER (notebook3), vbox11);
-
-  hbox33 = gtk_hbox_new (FALSE, 0);
-  gtk_widget_show (hbox33);
-  gtk_box_pack_start (GTK_BOX (vbox11), hbox33, TRUE, TRUE, 0);
-
-  label86 = gtk_label_new (_("Memory : "));
-  gtk_widget_show (label86);
-  gtk_box_pack_start (GTK_BOX (hbox33), label86, FALSE, FALSE, 0);
-  gtk_misc_set_padding (GTK_MISC (label86), 2, 0);
-
-  entry58 = gtk_entry_new ();
-  gtk_widget_show (entry58);
-  gtk_box_pack_start (GTK_BOX (hbox33), entry58, FALSE, FALSE, 0);
-  gtk_tooltips_set_tip (tooltips, entry58, _("example : 128"), NULL);
-  gtk_entry_set_max_length (GTK_ENTRY (entry58), 4);
-  gtk_entry_set_width_chars (GTK_ENTRY (entry58), 4);
-
-  label87 = gtk_label_new (_("megabytes."));
-  gtk_widget_show (label87);
-  gtk_box_pack_start (GTK_BOX (hbox33), label87, FALSE, FALSE, 0);
-  gtk_misc_set_padding (GTK_MISC (label87), 2, 0);
-
-  hbox34 = gtk_hbox_new (FALSE, 0);
-  gtk_widget_show (hbox34);
-  gtk_box_pack_start (GTK_BOX (vbox11), hbox34, TRUE, TRUE, 0);
-
-  label88 = gtk_label_new (_("Boot From"));
-  gtk_widget_show (label88);
-  gtk_box_pack_start (GTK_BOX (hbox34), label88, FALSE, FALSE, 0);
-
-  combobox7 = gtk_combo_box_new_text ();
-  gtk_widget_show (combobox7);
-  gtk_box_pack_start (GTK_BOX (hbox34), combobox7, TRUE, TRUE, 0);
-  gtk_combo_box_append_text (GTK_COMBO_BOX (combobox7), _("Floppy Disk A"));
-  gtk_combo_box_append_text (GTK_COMBO_BOX (combobox7), _("Floppy Disk B"));
-  gtk_combo_box_append_text (GTK_COMBO_BOX (combobox7), _("IDE0 - Master"));
-  gtk_combo_box_append_text (GTK_COMBO_BOX (combobox7), _("IDE0 - Slave"));
-  gtk_combo_box_append_text (GTK_COMBO_BOX (combobox7), _("IDE1 - Master"));
-  gtk_combo_box_append_text (GTK_COMBO_BOX (combobox7), _("IDE1 - Slave"));
-
-  frame7 = gtk_frame_new (NULL);
-  gtk_widget_show (frame7);
-  gtk_box_pack_start (GTK_BOX (vbox11), frame7, FALSE, FALSE, 0);
-  gtk_frame_set_shadow_type (GTK_FRAME (frame7), GTK_SHADOW_OUT);
-
-  alignment7 = gtk_alignment_new (0.5, 0.5, 1, 1);
-  gtk_widget_show (alignment7);
-  gtk_container_add (GTK_CONTAINER (frame7), alignment7);
-  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment7), 0, 0, 12, 0);
-
-  vbox12 = gtk_vbox_new (FALSE, 0);
-  gtk_widget_show (vbox12);
-  gtk_container_add (GTK_CONTAINER (alignment7), vbox12);
-
-  table13 = gtk_table_new (6, 3, FALSE);
-  gtk_widget_show (table13);
-  gtk_box_pack_start (GTK_BOX (vbox12), table13, FALSE, FALSE, 0);
-
-  entry59 = gtk_entry_new ();
-  gtk_widget_show (entry59);
-  gtk_table_attach (GTK_TABLE (table13), entry59, 1, 2, 1, 2,
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_entry_set_has_frame (GTK_ENTRY (entry59), FALSE);
-
-  entry60 = gtk_entry_new ();
-  gtk_widget_show (entry60);
-  gtk_table_attach (GTK_TABLE (table13), entry60, 1, 2, 2, 3,
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_entry_set_has_frame (GTK_ENTRY (entry60), FALSE);
-
-  entry61 = gtk_entry_new ();
-  gtk_widget_show (entry61);
-  gtk_table_attach (GTK_TABLE (table13), entry61, 1, 2, 3, 4,
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_entry_set_has_frame (GTK_ENTRY (entry61), FALSE);
-
-  entry62 = gtk_entry_new ();
-  gtk_widget_show (entry62);
-  gtk_table_attach (GTK_TABLE (table13), entry62, 1, 2, 5, 6,
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_entry_set_has_frame (GTK_ENTRY (entry62), FALSE);
-
-  button57 = gtk_button_new_from_stock ("gtk-open");
-  gtk_widget_show (button57);
-  gtk_table_attach (GTK_TABLE (table13), button57, 2, 3, 0, 1,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_button_set_relief (GTK_BUTTON (button57), GTK_RELIEF_NONE);
-  gtk_button_set_focus_on_click (GTK_BUTTON (button57), FALSE);
-
-  button58 = gtk_button_new_from_stock ("gtk-open");
-  gtk_widget_show (button58);
-  gtk_table_attach (GTK_TABLE (table13), button58, 2, 3, 1, 2,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_button_set_relief (GTK_BUTTON (button58), GTK_RELIEF_NONE);
-
-  button59 = gtk_button_new_from_stock ("gtk-open");
-  gtk_widget_show (button59);
-  gtk_table_attach (GTK_TABLE (table13), button59, 2, 3, 2, 3,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_button_set_relief (GTK_BUTTON (button59), GTK_RELIEF_NONE);
-
-  button60 = gtk_button_new_from_stock ("gtk-open");
-  gtk_widget_show (button60);
-  gtk_table_attach (GTK_TABLE (table13), button60, 2, 3, 3, 4,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_button_set_relief (GTK_BUTTON (button60), GTK_RELIEF_NONE);
-
-  button61 = gtk_button_new_from_stock ("gtk-open");
-  gtk_widget_show (button61);
-  gtk_table_attach (GTK_TABLE (table13), button61, 2, 3, 4, 5,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_button_set_relief (GTK_BUTTON (button61), GTK_RELIEF_NONE);
-
-  button62 = gtk_button_new_from_stock ("gtk-open");
-  gtk_widget_show (button62);
-  gtk_table_attach (GTK_TABLE (table13), button62, 2, 3, 5, 6,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_button_set_relief (GTK_BUTTON (button62), GTK_RELIEF_NONE);
-
-  entry63 = gtk_entry_new ();
-  gtk_widget_show (entry63);
-  gtk_table_attach (GTK_TABLE (table13), entry63, 1, 2, 4, 5,
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_entry_set_has_frame (GTK_ENTRY (entry63), FALSE);
-
-  entry64 = gtk_entry_new ();
-  gtk_widget_show (entry64);
-  gtk_table_attach (GTK_TABLE (table13), entry64, 1, 2, 0, 1,
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_entry_set_has_frame (GTK_ENTRY (entry64), FALSE);
-
-  checkbutton12 = gtk_check_button_new_with_mnemonic (_("Floppy Disk A"));
-  gtk_widget_show (checkbutton12);
-  gtk_table_attach (GTK_TABLE (table13), checkbutton12, 0, 1, 0, 1,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-
-  checkbutton13 = gtk_check_button_new_with_mnemonic (_("Floppy Disk B"));
-  gtk_widget_show (checkbutton13);
-  gtk_table_attach (GTK_TABLE (table13), checkbutton13, 0, 1, 1, 2,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-
-  checkbutton14 = gtk_check_button_new_with_mnemonic (_("IDE0 - Master"));
-  gtk_widget_show (checkbutton14);
-  gtk_table_attach (GTK_TABLE (table13), checkbutton14, 0, 1, 2, 3,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-
-  checkbutton15 = gtk_check_button_new_with_mnemonic (_("IDE1 - Master"));
-  gtk_widget_show (checkbutton15);
-  gtk_table_attach (GTK_TABLE (table13), checkbutton15, 0, 1, 4, 5,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-
-  checkbutton16 = gtk_check_button_new_with_mnemonic (_("IDE0 - Slave"));
-  gtk_widget_show (checkbutton16);
-  gtk_table_attach (GTK_TABLE (table13), checkbutton16, 0, 1, 3, 4,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-
-  checkbutton17 = gtk_check_button_new_with_mnemonic (_("IDE1 - Slave"));
-  gtk_widget_show (checkbutton17);
-  gtk_table_attach (GTK_TABLE (table13), checkbutton17, 0, 1, 5, 6,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-
-  hseparator2 = gtk_hseparator_new ();
-  gtk_widget_show (hseparator2);
-  gtk_box_pack_start (GTK_BOX (vbox12), hseparator2, FALSE, FALSE, 0);
-
-  checkbutton18 = gtk_check_button_new_with_mnemonic (_("IDE1 - Master is a CDROM"));
-  gtk_widget_show (checkbutton18);
-  gtk_box_pack_start (GTK_BOX (vbox12), checkbutton18, FALSE, FALSE, 0);
-  gtk_container_set_border_width (GTK_CONTAINER (checkbutton18), 10);
-  gtk_button_set_focus_on_click (GTK_BUTTON (checkbutton18), FALSE);
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton18), TRUE);
-
-  label89 = gtk_label_new (_("<b>Disk</b>"));
-  gtk_widget_show (label89);
-  gtk_frame_set_label_widget (GTK_FRAME (frame7), label89);
-  gtk_label_set_use_markup (GTK_LABEL (label89), TRUE);
-
-  label74 = gtk_label_new (_("Standard Options"));
-  gtk_widget_show (label74);
-  gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook3), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook3), 0), label74);
-
-  frame8 = gtk_frame_new (NULL);
-  gtk_widget_show (frame8);
-  gtk_container_add (GTK_CONTAINER (notebook3), frame8);
-  gtk_frame_set_shadow_type (GTK_FRAME (frame8), GTK_SHADOW_NONE);
-
-  alignment8 = gtk_alignment_new (0.5, 0.5, 1, 1);
-  gtk_widget_show (alignment8);
-  gtk_container_add (GTK_CONTAINER (frame8), alignment8);
-  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment8), 0, 0, 12, 0);
-
-  vbox13 = gtk_vbox_new (FALSE, 0);
-  gtk_widget_show (vbox13);
-  gtk_container_add (GTK_CONTAINER (alignment8), vbox13);
-
-  table14 = gtk_table_new (3, 3, FALSE);
-  gtk_widget_show (table14);
-  gtk_box_pack_start (GTK_BOX (vbox13), table14, FALSE, TRUE, 0);
-
-  entry65 = gtk_entry_new ();
-  gtk_widget_show (entry65);
-  gtk_table_attach (GTK_TABLE (table14), entry65, 1, 2, 0, 1,
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_tooltips_set_tip (tooltips, entry65, _("example : 00:40:F4:8A:32:D1"), NULL);
-  gtk_entry_set_max_length (GTK_ENTRY (entry65), 17);
-  gtk_entry_set_has_frame (GTK_ENTRY (entry65), FALSE);
-
-  entry66 = gtk_entry_new ();
-  gtk_widget_show (entry66);
-  gtk_table_attach (GTK_TABLE (table14), entry66, 1, 2, 1, 2,
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_tooltips_set_tip (tooltips, entry66, _("example : /netboot"), NULL);
-  gtk_entry_set_has_frame (GTK_ENTRY (entry66), FALSE);
-
-  entry67 = gtk_entry_new ();
-  gtk_widget_show (entry67);
-  gtk_table_attach (GTK_TABLE (table14), entry67, 1, 2, 2, 3,
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_tooltips_set_tip (tooltips, entry67, _("example : /share"), NULL);
-  gtk_entry_set_has_frame (GTK_ENTRY (entry67), FALSE);
-
-  button63 = gtk_button_new_from_stock ("gtk-open");
-  gtk_widget_show (button63);
-  gtk_table_attach (GTK_TABLE (table14), button63, 2, 3, 1, 2,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_button_set_relief (GTK_BUTTON (button63), GTK_RELIEF_NONE);
-
-  button64 = gtk_button_new_from_stock ("gtk-open");
-  gtk_widget_show (button64);
-  gtk_table_attach (GTK_TABLE (table14), button64, 2, 3, 2, 3,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_button_set_relief (GTK_BUTTON (button64), GTK_RELIEF_NONE);
-
-  label93 = gtk_label_new ("");
-  gtk_widget_show (label93);
-  gtk_table_attach (GTK_TABLE (table14), label93, 2, 3, 0, 1,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 7);
-  gtk_misc_set_alignment (GTK_MISC (label93), 0, 0.5);
-
-  label92 = gtk_label_new (_("SMB Local Access"));
-  gtk_widget_show (label92);
-  gtk_table_attach (GTK_TABLE (table14), label92, 0, 1, 2, 3,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 4, 0);
-  gtk_misc_set_alignment (GTK_MISC (label92), 0, 0.5);
-
-  label91 = gtk_label_new (_("TFTP Local Access"));
-  gtk_widget_show (label91);
-  gtk_table_attach (GTK_TABLE (table14), label91, 0, 1, 1, 2,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 4, 0);
-  gtk_misc_set_alignment (GTK_MISC (label91), 0, 0.5);
-
-  label90 = gtk_label_new (_("Mac Address"));
-  gtk_widget_show (label90);
-  gtk_table_attach (GTK_TABLE (table14), label90, 0, 1, 0, 1,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 4, 0);
-
-  frame9 = gtk_frame_new (NULL);
-  gtk_widget_show (frame9);
-  gtk_box_pack_start (GTK_BOX (vbox13), frame9, FALSE, FALSE, 0);
-  gtk_container_set_border_width (GTK_CONTAINER (frame9), 4);
-  gtk_frame_set_shadow_type (GTK_FRAME (frame9), GTK_SHADOW_IN);
-
-  alignment9 = gtk_alignment_new (0.5, 0.5, 1, 1);
-  gtk_widget_show (alignment9);
-  gtk_container_add (GTK_CONTAINER (frame9), alignment9);
-  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment9), 0, 4, 12, 4);
-
-  table15 = gtk_table_new (2, 1, FALSE);
-  gtk_widget_show (table15);
-  gtk_container_add (GTK_CONTAINER (alignment9), table15);
-
-  hbox35 = gtk_hbox_new (FALSE, 0);
-  gtk_widget_show (hbox35);
-  gtk_table_attach (GTK_TABLE (table15), hbox35, 0, 1, 0, 1,
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
-
-  combobox8 = gtk_combo_box_new_text ();
-  gtk_widget_show (combobox8);
-  gtk_box_pack_start (GTK_BOX (hbox35), combobox8, FALSE, FALSE, 0);
-  gtk_combo_box_append_text (GTK_COMBO_BOX (combobox8), _("TCP"));
-  gtk_combo_box_append_text (GTK_COMBO_BOX (combobox8), _("UDP"));
-
-  entry68 = gtk_entry_new ();
-  gtk_widget_show (entry68);
-  gtk_box_pack_start (GTK_BOX (hbox35), entry68, FALSE, FALSE, 0);
-  gtk_tooltips_set_tip (tooltips, entry68, _("Example : 80"), NULL);
-  gtk_entry_set_has_frame (GTK_ENTRY (entry68), FALSE);
-
-  label94 = gtk_label_new (_("host port to "));
-  gtk_widget_show (label94);
-  gtk_box_pack_start (GTK_BOX (hbox35), label94, TRUE, TRUE, 0);
-
-  entry69 = gtk_entry_new ();
-  gtk_widget_show (entry69);
-  gtk_box_pack_start (GTK_BOX (hbox35), entry69, FALSE, FALSE, 0);
-  gtk_tooltips_set_tip (tooltips, entry69, _("Example : 80"), NULL);
-  gtk_entry_set_has_frame (GTK_ENTRY (entry69), FALSE);
-
-  label95 = gtk_label_new (_("guest port."));
-  gtk_widget_show (label95);
-  gtk_box_pack_start (GTK_BOX (hbox35), label95, TRUE, TRUE, 0);
-
-  button65 = gtk_button_new_from_stock ("gtk-add");
-  gtk_widget_show (button65);
-  gtk_box_pack_start (GTK_BOX (hbox35), button65, FALSE, FALSE, 0);
-  gtk_button_set_relief (GTK_BUTTON (button65), GTK_RELIEF_NONE);
-
-  hbox36 = gtk_hbox_new (FALSE, 0);
-  gtk_widget_show (hbox36);
-  gtk_table_attach (GTK_TABLE (table15), hbox36, 0, 1, 1, 2,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
-
-  combobox9 = gtk_combo_box_new_text ();
-  gtk_widget_show (combobox9);
-  gtk_box_pack_start (GTK_BOX (hbox36), combobox9, TRUE, TRUE, 0);
-
-  button66 = gtk_button_new_from_stock ("gtk-remove");
-  gtk_widget_show (button66);
-  gtk_box_pack_start (GTK_BOX (hbox36), button66, FALSE, FALSE, 0);
-  gtk_button_set_relief (GTK_BUTTON (button66), GTK_RELIEF_NONE);
-
-  label96 = gtk_label_new (_("<b>Redirect</b>"));
-  gtk_widget_show (label96);
-  gtk_frame_set_label_widget (GTK_FRAME (frame9), label96);
-  gtk_label_set_use_markup (GTK_LABEL (label96), TRUE);
-
-  checkbutton19 = gtk_check_button_new_with_mnemonic (_("Activate Network Card"));
-  gtk_widget_show (checkbutton19);
-  gtk_frame_set_label_widget (GTK_FRAME (frame8), checkbutton19);
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbutton19), TRUE);
-
-  label81 = gtk_label_new (_("Network Options"));
-  gtk_widget_show (label81);
-  gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook3), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook3), 1), label81);
-
-  table16 = gtk_table_new (3, 2, FALSE);
-  gtk_widget_show (table16);
-  gtk_container_add (GTK_CONTAINER (notebook3), table16);
-
-  label97 = gtk_label_new (_("Monitor Redirect"));
-  gtk_widget_show (label97);
-  gtk_table_attach (GTK_TABLE (table16), label97, 0, 1, 0, 1,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_misc_set_alignment (GTK_MISC (label97), 0, 0.5);
-  gtk_misc_set_padding (GTK_MISC (label97), 0, 4);
-
-  label98 = gtk_label_new (_("Serial Redirect"));
-  gtk_widget_show (label98);
-  gtk_table_attach (GTK_TABLE (table16), label98, 0, 1, 1, 2,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_misc_set_alignment (GTK_MISC (label98), 0, 0.5);
-  gtk_misc_set_padding (GTK_MISC (label98), 0, 4);
-
-  label99 = gtk_label_new (_("Command Line"));
-  gtk_widget_show (label99);
-  gtk_table_attach (GTK_TABLE (table16), label99, 0, 1, 2, 3,
-                   (GtkAttachOptions) (GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 0);
-  gtk_misc_set_alignment (GTK_MISC (label99), 0, 0.5);
-  gtk_misc_set_padding (GTK_MISC (label99), 0, 4);
-
-  entry72 = gtk_entry_new ();
-  gtk_widget_show (entry72);
-  gtk_table_attach (GTK_TABLE (table16), entry72, 1, 2, 0, 1,
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 4);
-  gtk_entry_set_has_frame (GTK_ENTRY (entry72), FALSE);
-
-  entry70 = gtk_entry_new ();
-  gtk_widget_show (entry70);
-  gtk_table_attach (GTK_TABLE (table16), entry70, 1, 2, 1, 2,
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 4);
-  gtk_entry_set_has_frame (GTK_ENTRY (entry70), FALSE);
-
-  entry71 = gtk_entry_new ();
-  gtk_widget_show (entry71);
-  gtk_table_attach (GTK_TABLE (table16), entry71, 1, 2, 2, 3,
-                   (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
-                   (GtkAttachOptions) (0), 0, 4);
-  gtk_entry_set_has_frame (GTK_ENTRY (entry71), FALSE);
-
-  label85 = gtk_label_new (_("Debug/Expert Options"));
-  gtk_widget_show (label85);
-  gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook3), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook3), 2), label85);
-
-  hbuttonbox3 = gtk_hbutton_box_new ();
-  gtk_widget_show (hbuttonbox3);
-  gtk_box_pack_start (GTK_BOX (vbox10), hbuttonbox3, FALSE, FALSE, 0);
-  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox3), GTK_BUTTONBOX_END);
-
-  button55 = gtk_button_new_from_stock ("gtk-cancel");
-  gtk_widget_show (button55);
-  gtk_container_add (GTK_CONTAINER (hbuttonbox3), button55);
-  GTK_WIDGET_SET_FLAGS (button55, GTK_CAN_DEFAULT);
-
-  button56 = gtk_button_new_from_stock ("gtk-ok");
-  gtk_widget_show (button56);
-  gtk_container_add (GTK_CONTAINER (hbuttonbox3), button56);
-  GTK_WIDGET_SET_FLAGS (button56, GTK_CAN_DEFAULT);
-
-  /* Store pointers to all widgets, for use by lookup_widget(). */
-  GLADE_HOOKUP_OBJECT_NO_REF (winprefs3, winprefs3, "winprefs3");
-  GLADE_HOOKUP_OBJECT (winprefs3, vbox10, "vbox10");
-  GLADE_HOOKUP_OBJECT (winprefs3, notebook3, "notebook3");
-  GLADE_HOOKUP_OBJECT (winprefs3, vbox11, "vbox11");
-  GLADE_HOOKUP_OBJECT (winprefs3, hbox33, "hbox33");
-  GLADE_HOOKUP_OBJECT (winprefs3, label86, "label86");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry58, "entry58");
-  GLADE_HOOKUP_OBJECT (winprefs3, label87, "label87");
-  GLADE_HOOKUP_OBJECT (winprefs3, hbox34, "hbox34");
-  GLADE_HOOKUP_OBJECT (winprefs3, label88, "label88");
-  GLADE_HOOKUP_OBJECT (winprefs3, combobox7, "combobox7");
-  GLADE_HOOKUP_OBJECT (winprefs3, frame7, "frame7");
-  GLADE_HOOKUP_OBJECT (winprefs3, alignment7, "alignment7");
-  GLADE_HOOKUP_OBJECT (winprefs3, vbox12, "vbox12");
-  GLADE_HOOKUP_OBJECT (winprefs3, table13, "table13");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry59, "entry59");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry60, "entry60");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry61, "entry61");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry62, "entry62");
-  GLADE_HOOKUP_OBJECT (winprefs3, button57, "button57");
-  GLADE_HOOKUP_OBJECT (winprefs3, button58, "button58");
-  GLADE_HOOKUP_OBJECT (winprefs3, button59, "button59");
-  GLADE_HOOKUP_OBJECT (winprefs3, button60, "button60");
-  GLADE_HOOKUP_OBJECT (winprefs3, button61, "button61");
-  GLADE_HOOKUP_OBJECT (winprefs3, button62, "button62");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry63, "entry63");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry64, "entry64");
-  GLADE_HOOKUP_OBJECT (winprefs3, checkbutton12, "checkbutton12");
-  GLADE_HOOKUP_OBJECT (winprefs3, checkbutton13, "checkbutton13");
-  GLADE_HOOKUP_OBJECT (winprefs3, checkbutton14, "checkbutton14");
-  GLADE_HOOKUP_OBJECT (winprefs3, checkbutton15, "checkbutton15");
-  GLADE_HOOKUP_OBJECT (winprefs3, checkbutton16, "checkbutton16");
-  GLADE_HOOKUP_OBJECT (winprefs3, checkbutton17, "checkbutton17");
-  GLADE_HOOKUP_OBJECT (winprefs3, hseparator2, "hseparator2");
-  GLADE_HOOKUP_OBJECT (winprefs3, checkbutton18, "checkbutton18");
-  GLADE_HOOKUP_OBJECT (winprefs3, label89, "label89");
-  GLADE_HOOKUP_OBJECT (winprefs3, label74, "label74");
-  GLADE_HOOKUP_OBJECT (winprefs3, frame8, "frame8");
-  GLADE_HOOKUP_OBJECT (winprefs3, alignment8, "alignment8");
-  GLADE_HOOKUP_OBJECT (winprefs3, vbox13, "vbox13");
-  GLADE_HOOKUP_OBJECT (winprefs3, table14, "table14");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry65, "entry65");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry66, "entry66");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry67, "entry67");
-  GLADE_HOOKUP_OBJECT (winprefs3, button63, "button63");
-  GLADE_HOOKUP_OBJECT (winprefs3, button64, "button64");
-  GLADE_HOOKUP_OBJECT (winprefs3, label93, "label93");
-  GLADE_HOOKUP_OBJECT (winprefs3, label92, "label92");
-  GLADE_HOOKUP_OBJECT (winprefs3, label91, "label91");
-  GLADE_HOOKUP_OBJECT (winprefs3, label90, "label90");
-  GLADE_HOOKUP_OBJECT (winprefs3, frame9, "frame9");
-  GLADE_HOOKUP_OBJECT (winprefs3, alignment9, "alignment9");
-  GLADE_HOOKUP_OBJECT (winprefs3, table15, "table15");
-  GLADE_HOOKUP_OBJECT (winprefs3, hbox35, "hbox35");
-  GLADE_HOOKUP_OBJECT (winprefs3, combobox8, "combobox8");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry68, "entry68");
-  GLADE_HOOKUP_OBJECT (winprefs3, label94, "label94");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry69, "entry69");
-  GLADE_HOOKUP_OBJECT (winprefs3, label95, "label95");
-  GLADE_HOOKUP_OBJECT (winprefs3, button65, "button65");
-  GLADE_HOOKUP_OBJECT (winprefs3, hbox36, "hbox36");
-  GLADE_HOOKUP_OBJECT (winprefs3, combobox9, "combobox9");
-  GLADE_HOOKUP_OBJECT (winprefs3, button66, "button66");
-  GLADE_HOOKUP_OBJECT (winprefs3, label96, "label96");
-  GLADE_HOOKUP_OBJECT (winprefs3, checkbutton19, "checkbutton19");
-  GLADE_HOOKUP_OBJECT (winprefs3, label81, "label81");
-  GLADE_HOOKUP_OBJECT (winprefs3, table16, "table16");
-  GLADE_HOOKUP_OBJECT (winprefs3, label97, "label97");
-  GLADE_HOOKUP_OBJECT (winprefs3, label98, "label98");
-  GLADE_HOOKUP_OBJECT (winprefs3, label99, "label99");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry72, "entry72");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry70, "entry70");
-  GLADE_HOOKUP_OBJECT (winprefs3, entry71, "entry71");
-  GLADE_HOOKUP_OBJECT (winprefs3, label85, "label85");
-  GLADE_HOOKUP_OBJECT (winprefs3, hbuttonbox3, "hbuttonbox3");
-  GLADE_HOOKUP_OBJECT (winprefs3, button55, "button55");
-  GLADE_HOOKUP_OBJECT (winprefs3, button56, "button56");
-  GLADE_HOOKUP_OBJECT_NO_REF (winprefs3, tooltips, "tooltips");
-
-  return winprefs3;
-}
-
-GtkWidget*
-create_winmain (GtkWidget * winmain3, GtkWidget * vbox35, GtkWidget * scroll_window35)
-{
-  GtkWidget *menubar1;
-  GtkWidget *menuitem1;
-  GtkWidget *menuitem1_menu;
-  GtkWidget *nouveau1;
-  GtkWidget *ouvrir1;
-  GtkWidget *enregistrer1;
-  GtkWidget *enregistrer_sous1;
-  GtkWidget *separatormenuitem1;
-  GtkWidget *fermer1;
-  GtkWidget *image99;
-  GtkWidget *quitter1;
-  GtkWidget *menuitem2;
-  GtkWidget *menuitem2_menu;
-  GtkWidget *couper1;
-  GtkWidget *copier1;
-  GtkWidget *coller1;
-  GtkWidget *supprimer1;
-  GtkWidget *preferences1;
-  GtkWidget *image100;
-  GtkWidget *machine1;
-  GtkWidget *machine1_menu;
-  GtkWidget *run1;
-  GtkWidget *image101;
-  GtkWidget *run_in_a_snapshot1;
-  GtkWidget *image102;
-  GtkWidget *s__parateur1;
-  GtkWidget *pause2;
-  GtkWidget *image103;
-  GtkWidget *continue1;
-  GtkWidget *image104;
-  GtkWidget *reset1;
-  GtkWidget *image105;
-  GtkWidget *shutdown1;
-  GtkWidget *image106;
-  GtkWidget *menuitem3;
-  GtkWidget *menuitem3_menu;
-  GtkWidget *zoom1;
-  GtkWidget *image107;
-  GtkWidget *menuitem4;
-  GtkWidget *menuitem4_menu;
-  GtkWidget *___propos1;
-  GtkWidget *toolbar2;
-  GtkIconSize tmp_toolbar_icon_size;
-  GtkWidget *toolbutton3;
-  GtkWidget *toolbutton4;
-  GtkWidget *separatortoolitem1;
-  GtkWidget *tmp_image;
-  GtkWidget *toolbutton5;
-  GtkWidget *toolbutton6;
-  GtkWidget *toolbutton7;
-  GtkWidget *toolbutton8;
-  GtkWidget *separatortoolitem2;
-  GtkWidget *toolbutton1;
-  GtkWidget *toolbutton2;
-  GtkWidget *statusbar3;
-  GtkAccelGroup *accel_group;
-
-  accel_group = gtk_accel_group_new ();
-
-  menubar1 = gtk_menu_bar_new ();
-  gtk_widget_show (menubar1);
-  gtk_box_pack_start (GTK_BOX (vbox35), menubar1, FALSE, FALSE, 0);
-
-  menuitem1 = gtk_menu_item_new_with_mnemonic (_("_Fichier"));
-  gtk_widget_show (menuitem1);
-  gtk_container_add (GTK_CONTAINER (menubar1), menuitem1);
-
-  menuitem1_menu = gtk_menu_new ();
-  gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem1), menuitem1_menu);
-
-  nouveau1 = gtk_image_menu_item_new_from_stock ("gtk-new", accel_group);
-  gtk_widget_show (nouveau1);
-  gtk_container_add (GTK_CONTAINER (menuitem1_menu), nouveau1);
-
-  ouvrir1 = gtk_image_menu_item_new_from_stock ("gtk-open", accel_group);
-  gtk_widget_show (ouvrir1);
-  gtk_container_add (GTK_CONTAINER (menuitem1_menu), ouvrir1);
-
-  enregistrer1 = gtk_image_menu_item_new_from_stock ("gtk-save", accel_group);
-  gtk_widget_show (enregistrer1);
-  gtk_container_add (GTK_CONTAINER (menuitem1_menu), enregistrer1);
-
-  enregistrer_sous1 = gtk_image_menu_item_new_from_stock ("gtk-save-as", accel_group);
-  gtk_widget_show (enregistrer_sous1);
-  gtk_container_add (GTK_CONTAINER (menuitem1_menu), enregistrer_sous1);
-
-  separatormenuitem1 = gtk_separator_menu_item_new ();
-  gtk_widget_show (separatormenuitem1);
-  gtk_container_add (GTK_CONTAINER (menuitem1_menu), separatormenuitem1);
-  gtk_widget_set_sensitive (separatormenuitem1, FALSE);
-
-  fermer1 = gtk_image_menu_item_new_with_mnemonic (_("_Fermer"));
-  gtk_widget_show (fermer1);
-  gtk_container_add (GTK_CONTAINER (menuitem1_menu), fermer1);
-  gtk_widget_add_accelerator (fermer1, "activate", accel_group,
-                             GDK_W, GDK_CONTROL_MASK,
-                             GTK_ACCEL_VISIBLE);
-
-  image99 = gtk_image_new_from_stock ("gtk-close", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image99);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (fermer1), image99);
-
-  quitter1 = gtk_image_menu_item_new_from_stock ("gtk-quit", accel_group);
-  gtk_widget_show (quitter1);
-  gtk_container_add (GTK_CONTAINER (menuitem1_menu), quitter1);
-
-  menuitem2 = gtk_menu_item_new_with_mnemonic (_("_\303\211dition"));
-  gtk_widget_show (menuitem2);
-  gtk_container_add (GTK_CONTAINER (menubar1), menuitem2);
-
-  menuitem2_menu = gtk_menu_new ();
-  gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem2), menuitem2_menu);
-
-  couper1 = gtk_image_menu_item_new_from_stock ("gtk-cut", accel_group);
-  gtk_widget_show (couper1);
-  gtk_container_add (GTK_CONTAINER (menuitem2_menu), couper1);
-
-  copier1 = gtk_image_menu_item_new_from_stock ("gtk-copy", accel_group);
-  gtk_widget_show (copier1);
-  gtk_container_add (GTK_CONTAINER (menuitem2_menu), copier1);
-
-  coller1 = gtk_image_menu_item_new_from_stock ("gtk-paste", accel_group);
-  gtk_widget_show (coller1);
-  gtk_container_add (GTK_CONTAINER (menuitem2_menu), coller1);
-
-  supprimer1 = gtk_image_menu_item_new_from_stock ("gtk-delete", accel_group);
-  gtk_widget_show (supprimer1);
-  gtk_container_add (GTK_CONTAINER (menuitem2_menu), supprimer1);
-
-  preferences1 = gtk_image_menu_item_new_with_mnemonic (_("_Pr\303\251f\303\251rences"));
-  gtk_widget_show (preferences1);
-  gtk_container_add (GTK_CONTAINER (menuitem2_menu), preferences1);
-
-  image100 = gtk_image_new_from_stock ("gtk-properties", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image100);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (preferences1), image100);
-
-  machine1 = gtk_menu_item_new_with_mnemonic (_("Machine"));
-  gtk_widget_show (machine1);
-  gtk_container_add (GTK_CONTAINER (menubar1), machine1);
-
-  machine1_menu = gtk_menu_new ();
-  gtk_menu_item_set_submenu (GTK_MENU_ITEM (machine1), machine1_menu);
-
-  run1 = gtk_image_menu_item_new_with_mnemonic (_("_Run"));
-  gtk_widget_show (run1);
-  gtk_container_add (GTK_CONTAINER (machine1_menu), run1);
-
-  image101 = gtk_image_new_from_stock ("gtk-execute", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image101);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (run1), image101);
-
-  run_in_a_snapshot1 = gtk_image_menu_item_new_with_mnemonic (_("Run in a _snapshot"));
-  gtk_widget_show (run_in_a_snapshot1);
-  gtk_container_add (GTK_CONTAINER (machine1_menu), run_in_a_snapshot1);
-
-  image102 = gtk_image_new_from_stock ("gtk-execute", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image102);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (run_in_a_snapshot1), image102);
-
-  s__parateur1 = gtk_separator_menu_item_new ();
-  gtk_widget_show (s__parateur1);
-  gtk_container_add (GTK_CONTAINER (machine1_menu), s__parateur1);
-  gtk_widget_set_sensitive (s__parateur1, FALSE);
-
-  pause2 = gtk_image_menu_item_new_with_mnemonic (_("_Pause"));
-  gtk_widget_show (pause2);
-  gtk_container_add (GTK_CONTAINER (machine1_menu), pause2);
-
-  image103 = gtk_image_new_from_stock ("gtk-no", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image103);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (pause2), image103);
-
-  continue1 = gtk_image_menu_item_new_with_mnemonic (_("_Continue"));
-  gtk_widget_show (continue1);
-  gtk_container_add (GTK_CONTAINER (machine1_menu), continue1);
-
-  image104 = gtk_image_new_from_stock ("gtk-yes", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image104);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (continue1), image104);
-
-  reset1 = gtk_image_menu_item_new_with_mnemonic (_("_Reset"));
-  gtk_widget_show (reset1);
-  gtk_container_add (GTK_CONTAINER (machine1_menu), reset1);
-
-  image105 = gtk_image_new_from_stock ("gtk-refresh", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image105);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (reset1), image105);
-
-  shutdown1 = gtk_image_menu_item_new_with_mnemonic (_("_Shutdown"));
-  gtk_widget_show (shutdown1);
-  gtk_container_add (GTK_CONTAINER (machine1_menu), shutdown1);
-
-  image106 = gtk_image_new_from_stock ("gtk-stop", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image106);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (shutdown1), image106);
-
-  menuitem3 = gtk_menu_item_new_with_mnemonic (_("Afficha_ge"));
-  gtk_widget_show (menuitem3);
-  gtk_container_add (GTK_CONTAINER (menubar1), menuitem3);
-
-  menuitem3_menu = gtk_menu_new ();
-  gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem3), menuitem3_menu);
-
-  zoom1 = gtk_image_menu_item_new_with_mnemonic (_("_Zoom"));
-  gtk_widget_show (zoom1);
-  gtk_container_add (GTK_CONTAINER (menuitem3_menu), zoom1);
-
-  image107 = gtk_image_new_from_stock ("gtk-zoom-100", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image107);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (zoom1), image107);
-
-  menuitem4 = gtk_menu_item_new_with_mnemonic (_("_Aide"));
-  gtk_widget_show (menuitem4);
-  gtk_container_add (GTK_CONTAINER (menubar1), menuitem4);
-
-  menuitem4_menu = gtk_menu_new ();
-  gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem4), menuitem4_menu);
-
-  ___propos1 = gtk_menu_item_new_with_mnemonic (_("\303\200 _propos"));
-  gtk_widget_show (___propos1);
-  gtk_container_add (GTK_CONTAINER (menuitem4_menu), ___propos1);
-
-  toolbar2 = gtk_toolbar_new ();
-  gtk_widget_show (toolbar2);
-  gtk_box_pack_start (GTK_BOX (vbox35), toolbar2, FALSE, FALSE, 0);
-  gtk_toolbar_set_style (GTK_TOOLBAR (toolbar2), GTK_TOOLBAR_ICONS);
-  tmp_toolbar_icon_size = gtk_toolbar_get_icon_size (GTK_TOOLBAR (toolbar2));
-
-  toolbutton3 = (GtkWidget*) gtk_tool_button_new_from_stock ("gtk-execute");
-  gtk_widget_show (toolbutton3);
-  gtk_container_add (GTK_CONTAINER (toolbar2), toolbutton3);
-
-  toolbutton4 = (GtkWidget*) gtk_tool_button_new_from_stock ("gtk-stop");
-  gtk_widget_show (toolbutton4);
-  gtk_container_add (GTK_CONTAINER (toolbar2), toolbutton4);
-
-  separatortoolitem1 = (GtkWidget*) gtk_separator_tool_item_new ();
-  gtk_widget_show (separatortoolitem1);
-  gtk_container_add (GTK_CONTAINER (toolbar2), separatortoolitem1);
-
-  tmp_image = gtk_image_new_from_stock ("gtk-yes", tmp_toolbar_icon_size);
-  gtk_widget_show (tmp_image);
-  toolbutton5 = (GtkWidget*) gtk_tool_button_new (tmp_image, _("Continue"));
-  gtk_widget_show (toolbutton5);
-  gtk_container_add (GTK_CONTAINER (toolbar2), toolbutton5);
-
-  tmp_image = gtk_image_new_from_stock ("gtk-no", tmp_toolbar_icon_size);
-  gtk_widget_show (tmp_image);
-  toolbutton6 = (GtkWidget*) gtk_tool_button_new (tmp_image, _("Pause"));
-  gtk_widget_show (toolbutton6);
-  gtk_container_add (GTK_CONTAINER (toolbar2), toolbutton6);
-
-  tmp_image = gtk_image_new_from_stock ("gtk-refresh", tmp_toolbar_icon_size);
-  gtk_widget_show (tmp_image);
-  toolbutton7 = (GtkWidget*) gtk_tool_button_new (tmp_image, _("Reset"));
-  gtk_widget_show (toolbutton7);
-  gtk_container_add (GTK_CONTAINER (toolbar2), toolbutton7);
-
-  tmp_image = gtk_image_new_from_stock ("gtk-zoom-100", tmp_toolbar_icon_size);
-  gtk_widget_show (tmp_image);
-  toolbutton8 = (GtkWidget*) gtk_tool_button_new (tmp_image, _("Zoom"));
-  gtk_widget_show (toolbutton8);
-  gtk_container_add (GTK_CONTAINER (toolbar2), toolbutton8);
-
-  separatortoolitem2 = (GtkWidget*) gtk_separator_tool_item_new ();
-  gtk_widget_show (separatortoolitem2);
-  gtk_container_add (GTK_CONTAINER (toolbar2), separatortoolitem2);
-
-  toolbutton1 = (GtkWidget*) gtk_tool_button_new_from_stock ("gtk-help");
-  gtk_widget_show (toolbutton1);
-  gtk_container_add (GTK_CONTAINER (toolbar2), toolbutton1);
-
-  toolbutton2 = (GtkWidget*) gtk_tool_button_new_from_stock ("gtk-quit");
-  gtk_widget_show (toolbutton2);
-  gtk_container_add (GTK_CONTAINER (toolbar2), toolbutton2);
-
-  gtk_box_pack_start (GTK_BOX (vbox35), scroll_window35, TRUE, TRUE, 0);
-
-  statusbar3 = gtk_statusbar_new ();
-  gtk_widget_show (statusbar3);
-  gtk_box_pack_start (GTK_BOX (vbox35), statusbar3, FALSE, FALSE, 0);
-
-  g_signal_connect ((gpointer) nouveau1, "activate",
-                   G_CALLBACK (on_nouveau1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) ouvrir1, "activate",
-                   G_CALLBACK (on_ouvrir1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) enregistrer1, "activate",
-                   G_CALLBACK (on_enregistrer1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) enregistrer_sous1, "activate",
-                   G_CALLBACK (on_enregistrer_sous1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) fermer1, "activate",
-                   G_CALLBACK (on_fermer1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) quitter1, "activate",
-                   G_CALLBACK (on_quitter1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) couper1, "activate",
-                   G_CALLBACK (on_couper1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) copier1, "activate",
-                   G_CALLBACK (on_copier1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) coller1, "activate",
-                   G_CALLBACK (on_coller1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) supprimer1, "activate",
-                   G_CALLBACK (on_supprimer1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) preferences1, "activate",
-                   G_CALLBACK (on_preferences1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) machine1, "activate",
-                   G_CALLBACK (on_machine1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) run1, "activate",
-                   G_CALLBACK (on_run1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) run_in_a_snapshot1, "activate",
-                   G_CALLBACK (on_run_in_a_snapshot1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) pause2, "activate",
-                   G_CALLBACK (on_pause2_activate),
-                   NULL);
-  g_signal_connect ((gpointer) continue1, "activate",
-                   G_CALLBACK (on_continue1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) reset1, "activate",
-                   G_CALLBACK (on_reset1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) shutdown1, "activate",
-                   G_CALLBACK (on_shutdown1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) zoom1, "activate",
-                   G_CALLBACK (on_zoom1_activate),
-                   NULL);
-  g_signal_connect ((gpointer) ___propos1, "activate",
-                   G_CALLBACK (on____propos1_activate),
-                   NULL);
-
-  /* Store pointers to all widgets, for use by lookup_widget(). */
-  GLADE_HOOKUP_OBJECT_NO_REF (winmain3, winmain3, "winmain3");
-  GLADE_HOOKUP_OBJECT (winmain3, vbox35, "vbox35");
-  GLADE_HOOKUP_OBJECT (winmain3, menubar1, "menubar1");
-  GLADE_HOOKUP_OBJECT (winmain3, menuitem1, "menuitem1");
-  GLADE_HOOKUP_OBJECT (winmain3, menuitem1_menu, "menuitem1_menu");
-  GLADE_HOOKUP_OBJECT (winmain3, nouveau1, "nouveau1");
-  GLADE_HOOKUP_OBJECT (winmain3, ouvrir1, "ouvrir1");
-  GLADE_HOOKUP_OBJECT (winmain3, enregistrer1, "enregistrer1");
-  GLADE_HOOKUP_OBJECT (winmain3, enregistrer_sous1, "enregistrer_sous1");
-  GLADE_HOOKUP_OBJECT (winmain3, separatormenuitem1, "separatormenuitem1");
-  GLADE_HOOKUP_OBJECT (winmain3, fermer1, "fermer1");
-  GLADE_HOOKUP_OBJECT (winmain3, image99, "image99");
-  GLADE_HOOKUP_OBJECT (winmain3, quitter1, "quitter1");
-  GLADE_HOOKUP_OBJECT (winmain3, menuitem2, "menuitem2");
-  GLADE_HOOKUP_OBJECT (winmain3, menuitem2_menu, "menuitem2_menu");
-  GLADE_HOOKUP_OBJECT (winmain3, couper1, "couper1");
-  GLADE_HOOKUP_OBJECT (winmain3, copier1, "copier1");
-  GLADE_HOOKUP_OBJECT (winmain3, coller1, "coller1");
-  GLADE_HOOKUP_OBJECT (winmain3, supprimer1, "supprimer1");
-  GLADE_HOOKUP_OBJECT (winmain3, preferences1, "preferences1");
-  GLADE_HOOKUP_OBJECT (winmain3, image100, "image100");
-  GLADE_HOOKUP_OBJECT (winmain3, machine1, "machine1");
-  GLADE_HOOKUP_OBJECT (winmain3, machine1_menu, "machine1_menu");
-  GLADE_HOOKUP_OBJECT (winmain3, run1, "run1");
-  GLADE_HOOKUP_OBJECT (winmain3, image101, "image101");
-  GLADE_HOOKUP_OBJECT (winmain3, run_in_a_snapshot1, "run_in_a_snapshot1");
-  GLADE_HOOKUP_OBJECT (winmain3, image102, "image102");
-  GLADE_HOOKUP_OBJECT (winmain3, s__parateur1, "s__parateur1");
-  GLADE_HOOKUP_OBJECT (winmain3, pause2, "pause2");
-  GLADE_HOOKUP_OBJECT (winmain3, image103, "image103");
-  GLADE_HOOKUP_OBJECT (winmain3, continue1, "continue1");
-  GLADE_HOOKUP_OBJECT (winmain3, image104, "image104");
-  GLADE_HOOKUP_OBJECT (winmain3, reset1, "reset1");
-  GLADE_HOOKUP_OBJECT (winmain3, image105, "image105");
-  GLADE_HOOKUP_OBJECT (winmain3, shutdown1, "shutdown1");
-  GLADE_HOOKUP_OBJECT (winmain3, image106, "image106");
-  GLADE_HOOKUP_OBJECT (winmain3, menuitem3, "menuitem3");
-  GLADE_HOOKUP_OBJECT (winmain3, menuitem3_menu, "menuitem3_menu");
-  GLADE_HOOKUP_OBJECT (winmain3, zoom1, "zoom1");
-  GLADE_HOOKUP_OBJECT (winmain3, image107, "image107");
-  GLADE_HOOKUP_OBJECT (winmain3, menuitem4, "menuitem4");
-  GLADE_HOOKUP_OBJECT (winmain3, menuitem4_menu, "menuitem4_menu");
-  GLADE_HOOKUP_OBJECT (winmain3, ___propos1, "___propos1");
-  GLADE_HOOKUP_OBJECT (winmain3, toolbar2, "toolbar2");
-  GLADE_HOOKUP_OBJECT (winmain3, toolbutton3, "toolbutton3");
-  GLADE_HOOKUP_OBJECT (winmain3, toolbutton4, "toolbutton4");
-  GLADE_HOOKUP_OBJECT (winmain3, separatortoolitem1, "separatortoolitem1");
-  GLADE_HOOKUP_OBJECT (winmain3, toolbutton5, "toolbutton5");
-  GLADE_HOOKUP_OBJECT (winmain3, toolbutton6, "toolbutton6");
-  GLADE_HOOKUP_OBJECT (winmain3, toolbutton7, "toolbutton7");
-  GLADE_HOOKUP_OBJECT (winmain3, toolbutton8, "toolbutton8");
-  GLADE_HOOKUP_OBJECT (winmain3, separatortoolitem2, "separatortoolitem2");
-  GLADE_HOOKUP_OBJECT (winmain3, toolbutton1, "toolbutton1");
-  GLADE_HOOKUP_OBJECT (winmain3, toolbutton2, "toolbutton2");
-  GLADE_HOOKUP_OBJECT (winmain3, statusbar3, "statusbar3");
-
-  gtk_window_add_accel_group (GTK_WINDOW (winmain3), accel_group);
-
-  return winmain3;
-}
-
diff --git a/qemu-gtk/interface.h b/qemu-gtk/interface.h
deleted file mode 100644 (file)
index 7484575..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * DO NOT EDIT THIS FILE - it is generated by Glade.
- */
-
-GtkWidget* create_filechoosernew (void);
-GtkWidget* create_filechooseropen (void);
-GtkWidget* create_filechoosersave (void);
-GtkWidget* create_winprefs (void);
-GtkWidget* create_winmain (GtkWidget *, GtkWidget *, GtkWidget *);
diff --git a/qemu-gtk/null_fs.c b/qemu-gtk/null_fs.c
deleted file mode 100644 (file)
index 9135088..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* dummy functions - return successful but dont actually change the mode */
-/* use this with Win32 GTK until someone writes a win32_fs.c */
-
-int fullscreen_init(void)
-{
-       return 1;
-}
-
-int fullscreen_switch(int x, int y, int w, int h)
-{
-       return 1;
-}
-
-int fullscreen_reset(void)
-{
-       return 1;
-}
-
-void fullscreen_cleanup(void)
-{
-}
diff --git a/qemu-gtk/support.c b/qemu-gtk/support.c
deleted file mode 100644 (file)
index 00aff29..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * DO NOT EDIT THIS FILE - it is generated by Glade.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <gtk/gtk.h>
-
-#include "support.h"
-
-GtkWidget*
-lookup_widget                          (GtkWidget       *widget,
-                                        const gchar     *widget_name)
-{
-  GtkWidget *parent, *found_widget;
-
-  for (;;)
-    {
-      if (GTK_IS_MENU (widget))
-        parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
-      else
-        parent = widget->parent;
-      if (!parent)
-        parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey");
-      if (parent == NULL)
-        break;
-      widget = parent;
-    }
-
-  found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
-                                                 widget_name);
-  if (!found_widget)
-    g_warning ("Widget not found: %s", widget_name);
-  return found_widget;
-}
-
-static GList *pixmaps_directories = NULL;
-
-/* Use this function to set the directory containing installed pixmaps. */
-void
-add_pixmap_directory                   (const gchar     *directory)
-{
-  pixmaps_directories = g_list_prepend (pixmaps_directories,
-                                        g_strdup (directory));
-}
-
-/* This is an internally used function to find pixmap files. */
-static gchar*
-find_pixmap_file                       (const gchar     *filename)
-{
-  GList *elem;
-
-  /* We step through each of the pixmaps directory to find it. */
-  elem = pixmaps_directories;
-  while (elem)
-    {
-      gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data,
-                                         G_DIR_SEPARATOR_S, filename);
-      if (g_file_test (pathname, G_FILE_TEST_EXISTS))
-        return pathname;
-      g_free (pathname);
-      elem = elem->next;
-    }
-  return NULL;
-}
-
-/* This is an internally used function to create pixmaps. */
-GtkWidget*
-create_pixmap                          (GtkWidget       *widget,
-                                        const gchar     *filename)
-{
-  gchar *pathname = NULL;
-  GtkWidget *pixmap;
-
-  if (!filename || !filename[0])
-      return gtk_image_new ();
-
-  pathname = find_pixmap_file (filename);
-
-  if (!pathname)
-    {
-      g_warning (_("Couldn't find pixmap file: %s"), filename);
-      return gtk_image_new ();
-    }
-
-  pixmap = gtk_image_new_from_file (pathname);
-  g_free (pathname);
-  return pixmap;
-}
-
-/* This is an internally used function to create pixmaps. */
-GdkPixbuf*
-create_pixbuf                          (const gchar     *filename)
-{
-  gchar *pathname = NULL;
-  GdkPixbuf *pixbuf;
-  GError *error = NULL;
-
-  if (!filename || !filename[0])
-      return NULL;
-
-  pathname = find_pixmap_file (filename);
-
-  if (!pathname)
-    {
-      g_warning (_("Couldn't find pixmap file: %s"), filename);
-      return NULL;
-    }
-
-  pixbuf = gdk_pixbuf_new_from_file (pathname, &error);
-  if (!pixbuf)
-    {
-      fprintf (stderr, "Failed to load pixbuf file: %s: %s\n",
-               pathname, error->message);
-      g_error_free (error);
-    }
-  g_free (pathname);
-  return pixbuf;
-}
-
-/* This is used to set ATK action descriptions. */
-void
-glade_set_atk_action_description       (AtkAction       *action,
-                                        const gchar     *action_name,
-                                        const gchar     *description)
-{
-  gint n_actions, i;
-
-  n_actions = atk_action_get_n_actions (action);
-  for (i = 0; i < n_actions; i++)
-    {
-      if (!strcmp (atk_action_get_name (action, i), action_name))
-        atk_action_set_description (action, i, description);
-    }
-}
-
diff --git a/qemu-gtk/support.h b/qemu-gtk/support.h
deleted file mode 100644 (file)
index a32649e..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * DO NOT EDIT THIS FILE - it is generated by Glade.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include <gtk/gtk.h>
-
-/*
- * Standard gettext macros.
- */
-#ifdef ENABLE_NLS
-#  include <libintl.h>
-#  undef _
-#  define _(String) dgettext (PACKAGE, String)
-#  define Q_(String) g_strip_context ((String), gettext (String))
-#  ifdef gettext_noop
-#    define N_(String) gettext_noop (String)
-#  else
-#    define N_(String) (String)
-#  endif
-#else
-#  define textdomain(String) (String)
-#  define gettext(String) (String)
-#  define dgettext(Domain,Message) (Message)
-#  define dcgettext(Domain,Message,Type) (Message)
-#  define bindtextdomain(Domain,Directory) (Domain)
-#  define _(String) (String)
-#  define Q_(String) g_strip_context ((String), (String))
-#  define N_(String) (String)
-#endif
-
-
-/*
- * Public Functions.
- */
-
-/*
- * This function returns a widget in a component created by Glade.
- * Call it with the toplevel widget in the component (i.e. a window/dialog),
- * or alternatively any widget in the component, and the name of the widget
- * you want returned.
- */
-GtkWidget*  lookup_widget              (GtkWidget       *widget,
-                                        const gchar     *widget_name);
-
-
-/* Use this function to set the directory containing installed pixmaps. */
-void        add_pixmap_directory       (const gchar     *directory);
-
-
-/*
- * Private Functions.
- */
-
-/* This is used to create the pixmaps used in the interface. */
-GtkWidget*  create_pixmap              (GtkWidget       *widget,
-                                        const gchar     *filename);
-
-/* This is used to create the pixbufs used in the interface. */
-GdkPixbuf*  create_pixbuf              (const gchar     *filename);
-
-/* This is used to set ATK action descriptions. */
-void        glade_set_atk_action_description (AtkAction       *action,
-                                              const gchar     *action_name,
-                                              const gchar     *description);
-
diff --git a/qemu-gtk/xvid_fs.c b/qemu-gtk/xvid_fs.c
deleted file mode 100644 (file)
index 5f94bc0..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/* Use X11 Xvid extension to implement fullscreen mode */
-
-#include <stdlib.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/keysym.h>
-#include <X11/extensions/xf86dga.h>
-#include <X11/extensions/xf86vmode.h>
-
-static Display *dpy = NULL;
-static XF86VidModeModeInfo **mode_list = NULL;
-static XF86VidModeModeInfo * modeinfo = NULL;
-static int count = 0;
-
-int fullscreen_init(void)
-{
-       int event, error, dotclock;
-       XF86VidModeModeLine * modeline;
-
-       /* load up X display and make sure we have the Xvid extention */
-       dpy = XOpenDisplay(""); /* FIXME: make this the one that Gtk uses */
-       if (dpy == NULL)
-               return 0;
-       if (!XF86VidModeQueryExtension(dpy, &event, &error))
-               return 0;
-
-       /* get list of all modes */
-       XF86VidModeGetAllModeLines(dpy, XDefaultScreen(dpy), &count, &mode_list);
-
-       /* get current modeline */
-       modeline = (XF86VidModeModeLine *)malloc(sizeof(XF86VidModeModeLine));
-       XF86VidModeGetModeLine(dpy, XDefaultScreen(dpy), &dotclock, modeline);
-
-       /* convert to ModeInfo structure */
-       modeinfo = (XF86VidModeModeInfo *)malloc(sizeof(XF86VidModeModeInfo));
-       modeinfo->dotclock = dotclock;
-       modeinfo->hdisplay = modeline->hdisplay;
-       modeinfo->hsyncstart = modeline->hsyncstart;
-       modeinfo->hsyncend = modeline->hsyncend;
-       modeinfo->htotal = modeline->htotal;
-       modeinfo->vdisplay = modeline->vdisplay;
-       modeinfo->vsyncstart = modeline->vsyncstart;
-       modeinfo->vsyncend = modeline->vsyncend;
-       modeinfo->vtotal = modeline->vtotal;
-       modeinfo->flags = modeline->flags;
-       modeinfo->privsize = modeline->privsize;
-       modeinfo->private = modeline->private;
-       free(modeline);
-
-       return 1;
-}
-
-int fullscreen_switch(int x, int y, int w, int h)
-{
-       int i;
-       for (i = 0; i < count; i++)
-       {
-               if (w == mode_list[i]->hdisplay)
-                       if (h == mode_list[i]->vdisplay)
-                       {
-                               XF86VidModeSwitchToMode(dpy, XDefaultScreen(dpy), mode_list[i]);
-                               XF86VidModeSetViewPort(dpy, XDefaultScreen(dpy), 0, 0);
-                               XFlush(dpy);
-                               return 1;
-                       }
-       }
-       return 0;
-}
-
-int fullscreen_reset(void)
-{
-       XF86VidModeSwitchToMode(dpy, XDefaultScreen(dpy), modeinfo);
-       XFlush(dpy);
-       return 1;
-}
-
-void fullscreen_cleanup(void)
-{
-       int i;
-       if (modeinfo)
-       {
-               if (modeinfo->privsize != 0)
-                       free(modeinfo->private);
-               free(modeinfo);
-       }
-       if (mode_list)
-       {
-               for (i = 0; i < count; i++)
-               {
-                       if (mode_list[i])
-                       {
-                               if (mode_list[i]->privsize != 0)
-                                       free(mode_list[i]->private);
-                               //free(mode_list[i]);
-                       }
-               }
-               free(mode_list);
-       }
-}
index 8d9d296..b620678 100644 (file)
--- a/qemu.spec
+++ b/qemu.spec
@@ -3,7 +3,7 @@
 %define gtkver         20050716
 
 Name: qemu
-Version: 0.7.2
+Version: 0.8.0
 Release: alt1
 
 Summary: QEMU CPU Emulator
@@ -14,13 +14,10 @@ URL: http://fabrice.bellard.free.fr/qemu/
 Source: %name-%version.tar.bz2
 Source1: kqemu-%kqemuver.tar.gz
 Source2: kqemu-permission
-Source3: qemu-gtk-%gtkver.tar.bz2
 
 Patch: %name-0.7.1-alt-makefile.patch
 Patch1: %name-0.6.2-alt-hdtrans.patch
-Patch2: %name-0.7.0-alt-kqemu.patch
-Patch3: %name-0.7.2-gtk.patch
-Patch4: %name-0.7.1-alt-guiargs.patch
+Patch2: %name-0.8.0-alt-kqemu.patch
 
 # for %_bindir/qemu*
 %set_verify_elf_method textrel=relaxed
@@ -58,12 +55,10 @@ Group: Development/Kernel
 %kmodule_name modules sources for Linux kernel
 
 %prep
-%setup -q -a1 -a3
+%setup -q -a1
 %patch -p1
 %patch1 -p1
 %patch2 -p0
-%patch3 -p1
-%patch4 -p1
 
 %__cp -a kqemu kernel-source-%kmodule_name-%kqemuver
 %__cp -a %SOURCE2 kernel-source-%kmodule_name-%kqemuver/PERMISSION
@@ -97,6 +92,9 @@ cd tests
 %_usrsrc/kernel/sources/*
 
 %changelog
+* Wed Dec 21 2005 Kachalov Anton <mouse@altlinux.ru> 0.8.0-alt1
+- 0.8.0
+
 * Tue Sep 20 2005 Kachalov Anton <mouse@altlinux.ru> 0.7.2-alt1
 - 0.7.2
 - Updated Kqemu to 0.7.2
index 6d6858b..9ea66ba 100644 (file)
@@ -1,4 +1,5 @@
 arm-user
+arm-softmmu
 armeb-user
 config-host.*
 dyngen
@@ -21,3 +22,5 @@ x86_64-softmmu
 sparc64-user
 sparc64-softmmu
 mips-softmmu
+mips-user
+mipsel-user
index 3ba685b..4ad7cee 100644 (file)
@@ -1,3 +1,25 @@
+version 0.8.0:
+
+  - ARM system emulation: Arm Integrator/CP board with an arm1026ej-s
+    cpu (Paul Brook)
+  - SMP support
+  - Mac OS X cocoa improvements (Mike Kronenberg)
+  - Mac OS X CoreAudio driver (Mike Kronenberg)
+  - DirectSound driver (malc)
+  - ALSA audio driver (malc)
+  - new audio options: '-soundhw' and '-audio-help' (malc)
+  - ES1370 PCI audio device (malc)
+  - Initial USB support
+  - Linux host serial port access
+  - Linux host low level parallel port access
+  - New network emulation code supporting VLANs.
+  - MIPS and MIPSel User Linux emulation
+  - MIPS fixes to boot Linux (Daniel Jacobowitz)
+  - NX bit support
+  - Initial SPARC SMP support (Blue Swirl)
+  - Major overhaul of the virtual FAT driver for read/write support
+    (Johannes Schindelin)
+
 version 0.7.2:
   
   - x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit)
index 3320586..cfa7df5 100644 (file)
@@ -118,10 +118,14 @@ tarbin:
        $(bindir)/qemu-system-sparc \
        $(bindir)/qemu-system-x86_64 \
        $(bindir)/qemu-system-mips \
+       $(bindir)/qemu-system-arm \
        $(bindir)/qemu-i386 \
         $(bindir)/qemu-arm \
+        $(bindir)/qemu-armeb \
         $(bindir)/qemu-sparc \
         $(bindir)/qemu-ppc \
+        $(bindir)/qemu-mips \
+        $(bindir)/qemu-mipsel \
         $(bindir)/qemu-img \
        $(datadir)/bios.bin \
        $(datadir)/vgabios.bin \
index ea0f5c8..093d40c 100644 (file)
@@ -31,8 +31,16 @@ ifeq ($(TARGET_ARCH),arm)
     QEMU_USER=qemu-arm
   endif
 else
+ifeq ($(TARGET_ARCH),mips)
+  ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
+    QEMU_USER=qemu-mips
+  else
+    QEMU_USER=qemu-mipsel
+  endif
+else
   QEMU_USER=qemu-$(TARGET_ARCH)
 endif
+endif
 # system emulator name
 ifdef CONFIG_SOFTMMU
 ifeq ($(TARGET_ARCH), i386)
@@ -211,7 +219,7 @@ LIBOBJS+= op_helper.o helper.o
 endif
 
 ifeq ($(TARGET_BASE_ARCH), arm)
-LIBOBJS+= op_helper.o
+LIBOBJS+= op_helper.o helper.o
 endif
 
 # NOTE: the disassembler code is only needed for debugging
@@ -240,6 +248,9 @@ endif
 ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
 LIBOBJS+=arm-dis.o
 endif
+ifeq ($(findstring m68k, $(TARGET_ARCH) $(ARCH)),m68k)
+LIBOBJS+=m68k-dis.o
+endif
 
 ifeq ($(ARCH),ia64)
 OBJS += ia64-syscall.o
@@ -262,7 +273,7 @@ endif
 VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.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
 
-SOUND_HW = sb16.o
+SOUND_HW = sb16.o es1370.o
 AUDIODRV = audio.o noaudio.o wavaudio.o
 ifdef CONFIG_SDL
 AUDIODRV += sdlaudio.o
@@ -270,29 +281,41 @@ endif
 ifdef CONFIG_OSS
 AUDIODRV += ossaudio.o
 endif
-
-pc.o: DEFINES := -DUSE_SB16 $(DEFINES)
-
-ifdef CONFIG_ADLIB
-SOUND_HW += fmopl.o adlib.o
+ifdef CONFIG_COREAUDIO
+AUDIODRV += coreaudio.o
+endif
+ifdef CONFIG_ALSA
+AUDIODRV += alsaaudio.o
+LIBS += -lasound
+endif
+ifdef CONFIG_DSOUND
+AUDIODRV += dsoundaudio.o
+LIBS += -lole32 -ldxguid
 endif
-
 ifdef CONFIG_FMOD
 AUDIODRV += fmodaudio.o
 audio.o fmodaudio.o: DEFINES := -I$(CONFIG_FMOD_INC) $(DEFINES)
 LIBS += $(CONFIG_FMOD_LIB)
 endif
+ifdef CONFIG_ADLIB
+SOUND_HW += fmopl.o adlib.o
+endif
+
+# USB layer
+VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.o
 
 ifeq ($(TARGET_BASE_ARCH), i386)
 # Hardware support
-VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
+VL_OBJS+= ide.o ne2000.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
 VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
 VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o
+DEFINES += -DHAS_AUDIO
 endif
 ifeq ($(TARGET_BASE_ARCH), ppc)
-VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
+VL_OBJS+= ppc.o ide.o ne2000.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
+DEFINES += -DHAS_AUDIO
 endif
 ifeq ($(TARGET_ARCH), mips)
 VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8254.o i8259.o
@@ -300,14 +323,18 @@ VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8254.o i8259.o
 endif
 ifeq ($(TARGET_BASE_ARCH), sparc)
 ifeq ($(TARGET_ARCH), sparc64)
-VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o vga.o
+VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o ps2.o vga.o
 VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
 VL_OBJS+= cirrus_vga.o parallel.o
 VL_OBJS+= magic-load.o
 else
-VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t08.o magic-load.o slavio_intctl.o slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
+VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t59.o magic-load.o slavio_intctl.o
+VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
 endif
 endif
+ifeq ($(TARGET_BASE_ARCH), arm)
+VL_OBJS+= integratorcp.o ps2.o smc91c111.o
+endif
 ifdef CONFIG_GDBSTUB
 VL_OBJS+=gdbstub.o 
 endif
@@ -316,7 +343,10 @@ VL_OBJS+=sdl.o
 endif
 ifdef CONFIG_COCOA
 VL_OBJS+=cocoa.o
-COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa
+COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit
+ifdef CONFIG_COREAUDIO
+COCOA_LIBS+=-framework CoreAudio
+endif
 endif
 ifdef CONFIG_SLIRP
 DEFINES+=-I$(SRC_PATH)/slirp
@@ -348,6 +378,10 @@ ifeq ($(ARCH),ia64)
 VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
 endif
 
+ifdef CONFIG_WIN32
+SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole
+endif
+
 $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
        $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
 
@@ -363,6 +397,9 @@ sdlaudio.o: sdlaudio.c
 depend: $(SRCS)
        $(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
 
+vldepend: $(VL_OBJS:.o=.c)
+       $(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
+
 # libqemu 
 
 libqemu.a: $(LIBOBJS)
@@ -414,8 +451,6 @@ op.o: op.c op_template.c op_mem.c
 op_helper.o: op_helper_mem.c
 endif
 
-mixeng.o: mixeng.c mixeng.h mixeng_template.h
-
 %.o: %.c
        $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
 
@@ -433,3 +468,9 @@ endif
 ifneq ($(wildcard .depend),)
 include .depend
 endif
+
+ifeq (1, 0)
+audio.o sdlaudio.o dsoundaudio.o ossaudio.o wavaudio.o noaudio.o \
+fmodaudio.o alsaaudio.o mixeng.o sb16.o es1370.o gus.o adlib.o: \
+CFLAGS := $(CFLAGS) -Wall -Werror -W -Wsign-compare
+endif
index 088c26c..8cc9aa5 100644 (file)
--- a/qemu/TODO
+++ b/qemu/TODO
@@ -1,5 +1,9 @@
 short term:
 ----------
+- support variable tsc freq
+- cpu_interrupt() win32/SMP fix
+- USB host async
+- IDE async
 - debug option in 'configure' script + disable -fomit-frame-pointer
 - Precise VGA timings for old games/demos (malc patch)
 - merge PIC spurious interrupt patch
@@ -28,7 +32,6 @@ short term:
 - fix all remaining thread lock issues (must put TBs in a specific invalid
   state, find a solution for tb_flush()).
 - fix arm fpu rounding (at least for float->integer conversions)
-- SMP support
 
 ppc specific:
 ------------
@@ -36,22 +39,23 @@ ppc specific:
 - SPR_ENCODE() not useful
 - enable shift optimizations ?
 
-lower priority:
---------------
-- more friendly BIOS (logo)
-- int15 ah=86: use better timing
-- suppress shift_mem ops
-- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret)
-- optimize FPU operations (evaluate x87 stack pointer statically)
+linux-user specific:
+-------------------
 - add IPC syscalls
-- use -msoft-float on ARM
-- use kernel traps for unaligned accesses on ARM ?
 - handle rare page fault cases (in particular if page fault in helpers or
   in syscall emulation code).
-- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID)
 - more syscalls (in particular all 64 bit ones, IPCs, fix 64 bit
   issues, fix 16 bit uid issues)
 - use page_unprotect_range in every suitable syscall to handle all
   cases of self modifying code.
-- use gcc as a backend to generate better code (easy to do by using
-  op-i386.c operations as local inline functions).
+- fix thread stack freeing (use kernel 2.5.x CLONE_CHILD_CLEARTID)
+- use kernel traps for unaligned accesses on ARM ?
+
+
+lower priority:
+--------------
+- int15 ah=86: use better timing
+- suppress shift_mem ops
+- fix some 16 bit sp push/pop overflow (pusha/popa, lcall lret)
+- optimize FPU operations (evaluate x87 stack pointer statically)
+- use -msoft-float on ARM
index d5cc44d..8adc70f 100644 (file)
@@ -1 +1 @@
-0.7.2
\ No newline at end of file
+0.8.0
\ No newline at end of file
index e7a4fb4..81a55e9 100644 (file)
@@ -23,9 +23,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include <stdio.h>
 #include "dis-asm.h"
 
-#define ATTRIBUTE_UNUSED __attribute__((unused))
-#define _(x) x
-
 /* The opcode table is an array of struct alpha_opcode.  */
 
 struct alpha_opcode
diff --git a/qemu/audio/alsaaudio.c b/qemu/audio/alsaaudio.c
new file mode 100644 (file)
index 0000000..30f1e50
--- /dev/null
@@ -0,0 +1,981 @@
+/*
+ * QEMU ALSA audio driver
+ *
+ * Copyright (c) 2005 Vassili Karpov (malc)
+ *
+ * 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 <alsa/asoundlib.h>
+#include "vl.h"
+
+#define AUDIO_CAP "alsa"
+#include "audio_int.h"
+
+typedef struct ALSAVoiceOut {
+    HWVoiceOut hw;
+    void *pcm_buf;
+    snd_pcm_t *handle;
+} ALSAVoiceOut;
+
+typedef struct ALSAVoiceIn {
+    HWVoiceIn hw;
+    snd_pcm_t *handle;
+    void *pcm_buf;
+} ALSAVoiceIn;
+
+static struct {
+    int size_in_usec_in;
+    int size_in_usec_out;
+    const char *pcm_name_in;
+    const char *pcm_name_out;
+    unsigned int buffer_size_in;
+    unsigned int period_size_in;
+    unsigned int buffer_size_out;
+    unsigned int period_size_out;
+    unsigned int threshold;
+
+    int buffer_size_in_overriden;
+    int period_size_in_overriden;
+
+    int buffer_size_out_overriden;
+    int period_size_out_overriden;
+    int verbose;
+} conf = {
+#ifdef HIGH_LATENCY
+    .size_in_usec_in = 1,
+    .size_in_usec_out = 1,
+#endif
+    .pcm_name_out = "hw:0,0",
+    .pcm_name_in = "hw:0,0",
+#ifdef HIGH_LATENCY
+    .buffer_size_in = 400000,
+    .period_size_in = 400000 / 4,
+    .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,
+#endif
+    .threshold = 0,
+    .verbose = 0
+};
+
+struct alsa_params_req {
+    int freq;
+    audfmt_e fmt;
+    int nchannels;
+    unsigned int buffer_size;
+    unsigned int period_size;
+};
+
+struct alsa_params_obt {
+    int freq;
+    audfmt_e fmt;
+    int nchannels;
+    snd_pcm_uframes_t samples;
+};
+
+static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
+}
+
+static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
+    int err,
+    const char *typ,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
+}
+
+static void alsa_anal_close (snd_pcm_t **handlep)
+{
+    int err = snd_pcm_close (*handlep);
+    if (err) {
+        alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
+    }
+    *handlep = NULL;
+}
+
+static int alsa_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int aud_to_alsafmt (audfmt_e fmt)
+{
+    switch (fmt) {
+    case AUD_FMT_S8:
+        return SND_PCM_FORMAT_S8;
+
+    case AUD_FMT_U8:
+        return SND_PCM_FORMAT_U8;
+
+    case AUD_FMT_S16:
+        return SND_PCM_FORMAT_S16_LE;
+
+    case AUD_FMT_U16:
+        return SND_PCM_FORMAT_U16_LE;
+
+    default:
+        dolog ("Internal logic error: Bad audio format %d\n", fmt);
+#ifdef DEBUG_AUDIO
+        abort ();
+#endif
+        return SND_PCM_FORMAT_U8;
+    }
+}
+
+static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness)
+{
+    switch (alsafmt) {
+    case SND_PCM_FORMAT_S8:
+        *endianness = 0;
+        *fmt = AUD_FMT_S8;
+        break;
+
+    case SND_PCM_FORMAT_U8:
+        *endianness = 0;
+        *fmt = AUD_FMT_U8;
+        break;
+
+    case SND_PCM_FORMAT_S16_LE:
+        *endianness = 0;
+        *fmt = AUD_FMT_S16;
+        break;
+
+    case SND_PCM_FORMAT_U16_LE:
+        *endianness = 0;
+        *fmt = AUD_FMT_U16;
+        break;
+
+    case SND_PCM_FORMAT_S16_BE:
+        *endianness = 1;
+        *fmt = AUD_FMT_S16;
+        break;
+
+    case SND_PCM_FORMAT_U16_BE:
+        *endianness = 1;
+        *fmt = AUD_FMT_U16;
+        break;
+
+    default:
+        dolog ("Unrecognized audio format %d\n", alsafmt);
+        return -1;
+    }
+
+    return 0;
+}
+
+#if defined DEBUG_MISMATCHES || defined DEBUG
+static void alsa_dump_info (struct alsa_params_req *req,
+                            struct alsa_params_obt *obt)
+{
+    dolog ("parameter | requested value | obtained value\n");
+    dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
+    dolog ("channels  |      %10d |     %10d\n",
+           req->nchannels, obt->nchannels);
+    dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
+    dolog ("============================================\n");
+    dolog ("requested: buffer size %d period size %d\n",
+           req->buffer_size, req->period_size);
+    dolog ("obtained: samples %ld\n", obt->samples);
+}
+#endif
+
+static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
+{
+    int err;
+    snd_pcm_sw_params_t *sw_params;
+
+    snd_pcm_sw_params_alloca (&sw_params);
+
+    err = snd_pcm_sw_params_current (handle, sw_params);
+    if (err < 0) {
+        dolog ("Could not fully initialize DAC\n");
+        alsa_logerr (err, "Failed to get current software parameters\n");
+        return;
+    }
+
+    err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
+    if (err < 0) {
+        dolog ("Could not fully initialize DAC\n");
+        alsa_logerr (err, "Failed to set software threshold to %ld\n",
+                     threshold);
+        return;
+    }
+
+    err = snd_pcm_sw_params (handle, sw_params);
+    if (err < 0) {
+        dolog ("Could not fully initialize DAC\n");
+        alsa_logerr (err, "Failed to set software parameters\n");
+        return;
+    }
+}
+
+static int alsa_open (int in, struct alsa_params_req *req,
+                      struct alsa_params_obt *obt, snd_pcm_t **handlep)
+{
+    snd_pcm_t *handle;
+    snd_pcm_hw_params_t *hw_params;
+    int err, freq, nchannels;
+    const char *pcm_name = in ? conf.pcm_name_in : conf.pcm_name_out;
+    unsigned int period_size, buffer_size;
+    snd_pcm_uframes_t obt_buffer_size;
+    const char *typ = in ? "ADC" : "DAC";
+
+    freq = req->freq;
+    period_size = req->period_size;
+    buffer_size = req->buffer_size;
+    nchannels = req->nchannels;
+
+    snd_pcm_hw_params_alloca (&hw_params);
+
+    err = snd_pcm_open (
+        &handle,
+        pcm_name,
+        in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
+        SND_PCM_NONBLOCK
+        );
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
+        return -1;
+    }
+
+    err = snd_pcm_hw_params_any (handle, hw_params);
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
+        goto err;
+    }
+
+    err = snd_pcm_hw_params_set_access (
+        handle,
+        hw_params,
+        SND_PCM_ACCESS_RW_INTERLEAVED
+        );
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to set access type\n");
+        goto err;
+    }
+
+    err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
+        goto err;
+    }
+
+    err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
+        goto err;
+    }
+
+    err = snd_pcm_hw_params_set_channels_near (
+        handle,
+        hw_params,
+        &nchannels
+        );
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
+                      req->nchannels);
+        goto err;
+    }
+
+    if (nchannels != 1 && nchannels != 2) {
+        alsa_logerr2 (err, typ,
+                      "Can not handle obtained number of channels %d\n",
+                      nchannels);
+        goto err;
+    }
+
+    if (!((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out))) {
+        if (!buffer_size) {
+            buffer_size = DEFAULT_BUFFER_SIZE;
+            period_size= DEFAULT_PERIOD_SIZE;
+        }
+    }
+
+    if (buffer_size) {
+        if ((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out)) {
+            if (period_size) {
+                err = snd_pcm_hw_params_set_period_time_near (
+                    handle,
+                    hw_params,
+                    &period_size,
+                    0
+                    );
+                if (err < 0) {
+                    alsa_logerr2 (err, typ,
+                                  "Failed to set period time %d\n",
+                                  req->period_size);
+                    goto err;
+                }
+            }
+
+            err = snd_pcm_hw_params_set_buffer_time_near (
+                handle,
+                hw_params,
+                &buffer_size,
+                0
+                );
+
+            if (err < 0) {
+                alsa_logerr2 (err, typ,
+                              "Failed to set buffer time %d\n",
+                              req->buffer_size);
+                goto err;
+            }
+        }
+        else {
+            int dir;
+            snd_pcm_uframes_t minval;
+
+            if (period_size) {
+                minval = period_size;
+                dir = 0;
+
+                err = snd_pcm_hw_params_get_period_size_min (
+                    hw_params,
+                    &minval,
+                    &dir
+                    );
+                if (err < 0) {
+                    alsa_logerr (
+                        err,
+                        "Could not get minmal period size for %s\n",
+                        typ
+                        );
+                }
+                else {
+                    if (period_size < minval) {
+                        if ((in && conf.period_size_in_overriden)
+                            || (!in && conf.period_size_out_overriden)) {
+                            dolog ("%s period size(%d) is less "
+                                   "than minmal period size(%ld)\n",
+                                   typ,
+                                   period_size,
+                                   minval);
+                        }
+                        period_size = minval;
+                    }
+                }
+
+                err = snd_pcm_hw_params_set_period_size (
+                    handle,
+                    hw_params,
+                    period_size,
+                    0
+                    );
+                if (err < 0) {
+                    alsa_logerr2 (err, typ, "Failed to set period size %d\n",
+                                  req->period_size);
+                    goto err;
+                }
+            }
+
+            minval = buffer_size;
+            err = snd_pcm_hw_params_get_buffer_size_min (
+                hw_params,
+                &minval
+                );
+            if (err < 0) {
+                alsa_logerr (err, "Could not get minmal buffer size for %s\n",
+                             typ);
+            }
+            else {
+                if (buffer_size < minval) {
+                    if ((in && conf.buffer_size_in_overriden)
+                        || (!in && conf.buffer_size_out_overriden)) {
+                        dolog (
+                            "%s buffer size(%d) is less "
+                            "than minimal buffer size(%ld)\n",
+                            typ,
+                            buffer_size,
+                            minval
+                            );
+                    }
+                    buffer_size = minval;
+                }
+            }
+
+            err = snd_pcm_hw_params_set_buffer_size (
+                handle,
+                hw_params,
+                buffer_size
+                );
+            if (err < 0) {
+                alsa_logerr2 (err, typ, "Failed to set buffer size %d\n",
+                              req->buffer_size);
+                goto err;
+            }
+        }
+    }
+    else {
+        dolog ("warning: Buffer size is not set\n");
+    }
+
+    err = snd_pcm_hw_params (handle, hw_params);
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
+        goto err;
+    }
+
+    err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Failed to get buffer size\n");
+        goto err;
+    }
+
+    err = snd_pcm_prepare (handle);
+    if (err < 0) {
+        alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
+        goto err;
+    }
+
+    if (!in && conf.threshold) {
+        snd_pcm_uframes_t threshold;
+        int bytes_per_sec;
+
+        bytes_per_sec = freq
+            << (nchannels == 2)
+            << (req->fmt == AUD_FMT_S16 || req->fmt == AUD_FMT_U16);
+
+        threshold = (conf.threshold * bytes_per_sec) / 1000;
+        alsa_set_threshold (handle, threshold);
+    }
+
+    obt->fmt = req->fmt;
+    obt->nchannels = nchannels;
+    obt->freq = freq;
+    obt->samples = obt_buffer_size;
+    *handlep = handle;
+
+#if defined DEBUG_MISMATCHES || defined DEBUG
+    if (obt->fmt != req->fmt ||
+        obt->nchannels != req->nchannels ||
+        obt->freq != req->freq) {
+        dolog ("Audio paramters mismatch for %s\n", typ);
+        alsa_dump_info (req, obt);
+    }
+#endif
+
+#ifdef DEBUG
+    alsa_dump_info (req, obt);
+#endif
+    return 0;
+
+ err:
+    alsa_anal_close (&handle);
+    return -1;
+}
+
+static int alsa_recover (snd_pcm_t *handle)
+{
+    int err = snd_pcm_prepare (handle);
+    if (err < 0) {
+        alsa_logerr (err, "Failed to prepare handle %p\n", handle);
+        return -1;
+    }
+    return 0;
+}
+
+static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
+{
+    snd_pcm_sframes_t avail;
+
+    avail = snd_pcm_avail_update (handle);
+    if (avail < 0) {
+        if (avail == -EPIPE) {
+            if (!alsa_recover (handle)) {
+                avail = snd_pcm_avail_update (handle);
+            }
+        }
+
+        if (avail < 0) {
+            alsa_logerr (avail,
+                         "Could not obtain number of available frames\n");
+            return -1;
+        }
+    }
+
+    return avail;
+}
+
+static int alsa_run_out (HWVoiceOut *hw)
+{
+    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+    int rpos, live, decr;
+    int samples;
+    uint8_t *dst;
+    st_sample_t *src;
+    snd_pcm_sframes_t avail;
+
+    live = audio_pcm_hw_get_live_out (hw);
+    if (!live) {
+        return 0;
+    }
+
+    avail = alsa_get_avail (alsa->handle);
+    if (avail < 0) {
+        dolog ("Could not get number of available playback frames\n");
+        return 0;
+    }
+
+    decr = audio_MIN (live, avail);
+    samples = decr;
+    rpos = hw->rpos;
+    while (samples) {
+        int left_till_end_samples = hw->samples - rpos;
+        int len = audio_MIN (samples, left_till_end_samples);
+        snd_pcm_sframes_t written;
+
+        src = hw->mix_buf + rpos;
+        dst = advance (alsa->pcm_buf, rpos << hw->info.shift);
+
+        hw->clip (dst, src, len);
+
+        while (len) {
+            written = snd_pcm_writei (alsa->handle, dst, len);
+
+            if (written <= 0) {
+                switch (written) {
+                case 0:
+                    if (conf.verbose) {
+                        dolog ("Failed to write %d frames (wrote zero)\n", len);
+                    }
+                    goto exit;
+
+                case -EPIPE:
+                    if (alsa_recover (alsa->handle)) {
+                        alsa_logerr (written, "Failed to write %d frames\n",
+                                     len);
+                        goto exit;
+                    }
+                    if (conf.verbose) {
+                        dolog ("Recovering from playback xrun\n");
+                    }
+                    continue;
+
+                case -EAGAIN:
+                    goto exit;
+
+                default:
+                    alsa_logerr (written, "Failed to write %d frames to %p\n",
+                                 len, dst);
+                    goto exit;
+                }
+            }
+
+            mixeng_clear (src, written);
+            rpos = (rpos + written) % hw->samples;
+            samples -= written;
+            len -= written;
+            dst = advance (dst, written << hw->info.shift);
+            src += written;
+        }
+    }
+
+ exit:
+    hw->rpos = rpos;
+    return decr;
+}
+
+static void alsa_fini_out (HWVoiceOut *hw)
+{
+    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+
+    ldebug ("alsa_fini\n");
+    alsa_anal_close (&alsa->handle);
+
+    if (alsa->pcm_buf) {
+        qemu_free (alsa->pcm_buf);
+        alsa->pcm_buf = NULL;
+    }
+}
+
+static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
+{
+    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+    struct alsa_params_req req;
+    struct alsa_params_obt obt;
+    audfmt_e effective_fmt;
+    int endianness;
+    int err;
+    snd_pcm_t *handle;
+    audsettings_t obt_as;
+
+    req.fmt = aud_to_alsafmt (as->fmt);
+    req.freq = as->freq;
+    req.nchannels = as->nchannels;
+    req.period_size = conf.period_size_out;
+    req.buffer_size = conf.buffer_size_out;
+
+    if (alsa_open (0, &req, &obt, &handle)) {
+        return -1;
+    }
+
+    err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
+    if (err) {
+        alsa_anal_close (&handle);
+        return -1;
+    }
+
+    obt_as.freq = obt.freq;
+    obt_as.nchannels = obt.nchannels;
+    obt_as.fmt = effective_fmt;
+
+    audio_pcm_init_info (
+        &hw->info,
+        &obt_as,
+        audio_need_to_swap_endian (endianness)
+        );
+    hw->samples = obt.samples;
+
+    alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
+    if (!alsa->pcm_buf) {
+        dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
+               hw->samples, 1 << hw->info.shift);
+        alsa_anal_close (&handle);
+        return -1;
+    }
+
+    alsa->handle = handle;
+    return 0;
+}
+
+static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
+{
+    int err;
+
+    if (pause) {
+        err = snd_pcm_drop (handle);
+        if (err < 0) {
+            alsa_logerr (err, "Could not stop %s\n", typ);
+            return -1;
+        }
+    }
+    else {
+        err = snd_pcm_prepare (handle);
+        if (err < 0) {
+            alsa_logerr (err, "Could not prepare handle for %s\n", typ);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        ldebug ("enabling voice\n");
+        return alsa_voice_ctl (alsa->handle, "playback", 0);
+
+    case VOICE_DISABLE:
+        ldebug ("disabling voice\n");
+        return alsa_voice_ctl (alsa->handle, "playback", 1);
+    }
+
+    return -1;
+}
+
+static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
+{
+    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
+    struct alsa_params_req req;
+    struct alsa_params_obt obt;
+    int endianness;
+    int err;
+    audfmt_e effective_fmt;
+    snd_pcm_t *handle;
+    audsettings_t obt_as;
+
+    req.fmt = aud_to_alsafmt (as->fmt);
+    req.freq = as->freq;
+    req.nchannels = as->nchannels;
+    req.period_size = conf.period_size_in;
+    req.buffer_size = conf.buffer_size_in;
+
+    if (alsa_open (1, &req, &obt, &handle)) {
+        return -1;
+    }
+
+    err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
+    if (err) {
+        alsa_anal_close (&handle);
+        return -1;
+    }
+
+    obt_as.freq = obt.freq;
+    obt_as.nchannels = obt.nchannels;
+    obt_as.fmt = effective_fmt;
+
+    audio_pcm_init_info (
+        &hw->info,
+        &obt_as,
+        audio_need_to_swap_endian (endianness)
+        );
+    hw->samples = obt.samples;
+
+    alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+    if (!alsa->pcm_buf) {
+        dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
+               hw->samples, 1 << hw->info.shift);
+        alsa_anal_close (&handle);
+        return -1;
+    }
+
+    alsa->handle = handle;
+    return 0;
+}
+
+static void alsa_fini_in (HWVoiceIn *hw)
+{
+    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
+
+    alsa_anal_close (&alsa->handle);
+
+    if (alsa->pcm_buf) {
+        qemu_free (alsa->pcm_buf);
+        alsa->pcm_buf = NULL;
+    }
+}
+
+static int alsa_run_in (HWVoiceIn *hw)
+{
+    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
+    int hwshift = hw->info.shift;
+    int i;
+    int live = audio_pcm_hw_get_live_in (hw);
+    int dead = hw->samples - live;
+    int decr;
+    struct {
+        int add;
+        int len;
+    } bufs[2] = {
+        { hw->wpos, 0 },
+        { 0, 0 }
+    };
+    snd_pcm_sframes_t avail;
+    snd_pcm_uframes_t read_samples = 0;
+
+    if (!dead) {
+        return 0;
+    }
+
+    avail = alsa_get_avail (alsa->handle);
+    if (avail < 0) {
+        dolog ("Could not get number of captured frames\n");
+        return 0;
+    }
+
+    if (!avail && (snd_pcm_state (alsa->handle) == SND_PCM_STATE_PREPARED)) {
+        avail = hw->samples;
+    }
+
+    decr = audio_MIN (dead, avail);
+    if (!decr) {
+        return 0;
+    }
+
+    if (hw->wpos + decr > hw->samples) {
+        bufs[0].len = (hw->samples - hw->wpos);
+        bufs[1].len = (decr - (hw->samples - hw->wpos));
+    }
+    else {
+        bufs[0].len = decr;
+    }
+
+    for (i = 0; i < 2; ++i) {
+        void *src;
+        st_sample_t *dst;
+        snd_pcm_sframes_t nread;
+        snd_pcm_uframes_t len;
+
+        len = bufs[i].len;
+
+        src = advance (alsa->pcm_buf, bufs[i].add << hwshift);
+        dst = hw->conv_buf + bufs[i].add;
+
+        while (len) {
+            nread = snd_pcm_readi (alsa->handle, src, len);
+
+            if (nread <= 0) {
+                switch (nread) {
+                case 0:
+                    if (conf.verbose) {
+                        dolog ("Failed to read %ld frames (read zero)\n", len);
+                    }
+                    goto exit;
+
+                case -EPIPE:
+                    if (alsa_recover (alsa->handle)) {
+                        alsa_logerr (nread, "Failed to read %ld frames\n", len);
+                        goto exit;
+                    }
+                    if (conf.verbose) {
+                        dolog ("Recovering from capture xrun\n");
+                    }
+                    continue;
+
+                case -EAGAIN:
+                    goto exit;
+
+                default:
+                    alsa_logerr (
+                        nread,
+                        "Failed to read %ld frames from %p\n",
+                        len,
+                        src
+                        );
+                    goto exit;
+                }
+            }
+
+            hw->conv (dst, src, nread, &nominal_volume);
+
+            src = advance (src, nread << hwshift);
+            dst += nread;
+
+            read_samples += nread;
+            len -= nread;
+        }
+    }
+
+ exit:
+    hw->wpos = (hw->wpos + read_samples) % hw->samples;
+    return read_samples;
+}
+
+static int alsa_read (SWVoiceIn *sw, void *buf, int size)
+{
+    return audio_pcm_sw_read (sw, buf, size);
+}
+
+static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+    ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        ldebug ("enabling voice\n");
+        return alsa_voice_ctl (alsa->handle, "capture", 0);
+
+    case VOICE_DISABLE:
+        ldebug ("disabling voice\n");
+        return alsa_voice_ctl (alsa->handle, "capture", 1);
+    }
+
+    return -1;
+}
+
+static void *alsa_audio_init (void)
+{
+    return &conf;
+}
+
+static void alsa_audio_fini (void *opaque)
+{
+    (void) opaque;
+}
+
+static struct audio_option alsa_options[] = {
+    {"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_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,
+     "DAC buffer size", &conf.buffer_size_out_overriden, 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_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,
+     "ADC buffer size", &conf.buffer_size_in_overriden, 0},
+
+    {"THRESHOLD", AUD_OPT_INT, &conf.threshold,
+     "(undocumented)", NULL, 0},
+
+    {"DAC_DEV", AUD_OPT_STR, &conf.pcm_name_out,
+     "DAC device name (for instance dmix)", NULL, 0},
+
+    {"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in,
+     "ADC device name", NULL, 0},
+
+    {"VERBOSE", AUD_OPT_BOOL, &conf.verbose,
+     "Behave in a more verbose way", NULL, 0},
+
+    {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+static struct audio_pcm_ops alsa_pcm_ops = {
+    alsa_init_out,
+    alsa_fini_out,
+    alsa_run_out,
+    alsa_write,
+    alsa_ctl_out,
+
+    alsa_init_in,
+    alsa_fini_in,
+    alsa_run_in,
+    alsa_read,
+    alsa_ctl_in
+};
+
+struct audio_driver alsa_audio_driver = {
+    INIT_FIELD (name           = ) "alsa",
+    INIT_FIELD (descr          = ) "ALSA http://www.alsa-project.org",
+    INIT_FIELD (options        = ) alsa_options,
+    INIT_FIELD (init           = ) alsa_audio_init,
+    INIT_FIELD (fini           = ) alsa_audio_fini,
+    INIT_FIELD (pcm_ops        = ) &alsa_pcm_ops,
+    INIT_FIELD (can_be_default = ) 1,
+    INIT_FIELD (max_voices_out = ) INT_MAX,
+    INIT_FIELD (max_voices_in  = ) INT_MAX,
+    INIT_FIELD (voice_size_out = ) sizeof (ALSAVoiceOut),
+    INIT_FIELD (voice_size_in  = ) sizeof (ALSAVoiceIn)
+};
index 0c0c8dd..7634535 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * QEMU Audio subsystem
- * 
- * Copyright (c) 2003-2004 Vassili Karpov (malc)
- * 
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
  * 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
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include <assert.h>
 #include "vl.h"
 
-#define USE_WAV_AUDIO
+#define AUDIO_CAP "audio"
+#include "audio_int.h"
 
-#include "audio/audio_int.h"
+/* #define DEBUG_PLIVE */
+/* #define DEBUG_LIVE */
+/* #define DEBUG_OUT */
 
-#define dolog(...) AUD_log ("audio", __VA_ARGS__)
-#ifdef DEBUG
-#define ldebug(...) dolog (__VA_ARGS__)
-#else
-#define ldebug(...)
+#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
+
+static struct audio_driver *drvtab[] = {
+#ifdef CONFIG_OSS
+    &oss_audio_driver,
+#endif
+#ifdef CONFIG_ALSA
+    &alsa_audio_driver,
+#endif
+#ifdef CONFIG_COREAUDIO
+    &coreaudio_audio_driver,
+#endif
+#ifdef CONFIG_DSOUND
+    &dsound_audio_driver,
+#endif
+#ifdef CONFIG_FMOD
+    &fmod_audio_driver,
 #endif
+#ifdef CONFIG_SDL
+    &sdl_audio_driver,
+#endif
+    &no_audio_driver,
+    &wav_audio_driver
+};
+
+struct fixed_settings {
+    int enabled;
+    int nb_voices;
+    int greedy;
+    audsettings_t settings;
+};
+
+static struct {
+    struct fixed_settings fixed_out;
+    struct fixed_settings fixed_in;
+    union {
+        int hz;
+        int64_t ticks;
+    } period;
+    int plive;
+    int log_to_monitor;
+} conf = {
+    {                           /* DAC fixed settings */
+        1,                      /* enabled */
+        1,                      /* nb_voices */
+        1,                      /* greedy */
+        {
+            44100,              /* freq */
+            2,                  /* nchannels */
+            AUD_FMT_S16         /* fmt */
+        }
+    },
+
+    {                           /* ADC fixed settings */
+        1,                      /* enabled */
+        1,                      /* nb_voices */
+        1,                      /* greedy */
+        {
+            44100,              /* freq */
+            2,                  /* nchannels */
+            AUD_FMT_S16         /* fmt */
+        }
+    },
 
-#define QC_AUDIO_DRV    "QEMU_AUDIO_DRV"
-#define QC_VOICES       "QEMU_VOICES"
-#define QC_FIXED_FORMAT "QEMU_FIXED_FORMAT"
-#define QC_FIXED_FREQ   "QEMU_FIXED_FREQ"
+    { 0 },                      /* period */
+    0,                          /* plive */
+    0                           /* log_to_monitor */
+};
 
-static HWVoice *hw_voices;
+static AudioState glob_audio_state;
 
-AudioState audio_state = {
-    1,                          /* use fixed settings */
-    44100,                      /* fixed frequency */
-    2,                          /* fixed channels */
-    AUD_FMT_S16,                /* fixed format */
-    1,                          /* number of hw voices */
-    -1                          /* voice size */
+volume_t nominal_volume = {
+    0,
+#ifdef FLOAT_MIXENG
+    1.0,
+    1.0
+#else
+    UINT_MAX,
+    UINT_MAX
+#endif
 };
 
 /* http://www.df.lth.se/~john_e/gems/gem002d.html */
@@ -68,74 +129,445 @@ inline uint32_t lsbindex (uint32_t u)
     return popcount ((u&-u)-1);
 }
 
-int audio_get_conf_int (const char *key, int defval)
+#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
+#error No its not
+#else
+int audio_bug (const char *funcname, int cond)
+{
+    if (cond) {
+        static int shown;
+
+        AUD_log (NULL, "Error a bug that was just triggered in %s\n", funcname);
+        if (!shown) {
+            shown = 1;
+            AUD_log (NULL, "Save all your work and restart without audio\n");
+            AUD_log (NULL, "Please send bug report to malc@pulsesoft.com\n");
+            AUD_log (NULL, "I am sorry\n");
+        }
+        AUD_log (NULL, "Context:\n");
+
+#if defined AUDIO_BREAKPOINT_ON_BUG
+#  if defined HOST_I386
+#    if defined __GNUC__
+        __asm__ ("int3");
+#    elif defined _MSC_VER
+        _asm _emit 0xcc;
+#    else
+        abort ();
+#    endif
+#  else
+        abort ();
+#  endif
+#endif
+    }
+
+    return cond;
+}
+#endif
+
+void *audio_calloc (const char *funcname, int nmemb, size_t size)
+{
+    int cond;
+    size_t len;
+
+    len = nmemb * size;
+    cond = !nmemb || !size;
+    cond |= nmemb < 0;
+    cond |= len < size;
+
+    if (audio_bug ("audio_calloc", cond)) {
+        AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n",
+                 funcname);
+        AUD_log (NULL, "nmemb=%d size=%zu (len=%zu)\n", nmemb, size, len);
+        return NULL;
+    }
+
+    return qemu_mallocz (len);
+}
+
+static char *audio_alloc_prefix (const char *s)
+{
+    const char qemu_prefix[] = "QEMU_";
+    size_t len;
+    char *r;
+
+    if (!s) {
+        return NULL;
+    }
+
+    len = strlen (s);
+    r = qemu_malloc (len + sizeof (qemu_prefix));
+
+    if (r) {
+        size_t i;
+        char *u = r + sizeof (qemu_prefix) - 1;
+
+        strcpy (r, qemu_prefix);
+        strcat (r, s);
+
+        for (i = 0; i < len; ++i) {
+            u[i] = toupper (u[i]);
+        }
+    }
+    return r;
+}
+
+const char *audio_audfmt_to_string (audfmt_e fmt)
+{
+    switch (fmt) {
+    case AUD_FMT_U8:
+        return "U8";
+
+    case AUD_FMT_U16:
+        return "U16";
+
+    case AUD_FMT_S8:
+        return "S8";
+
+    case AUD_FMT_S16:
+        return "S16";
+    }
+
+    dolog ("Bogus audfmt %d returning S16\n", fmt);
+    return "S16";
+}
+
+audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp)
 {
-    int val = defval;
+    if (!strcasecmp (s, "u8")) {
+        *defaultp = 0;
+        return AUD_FMT_U8;
+    }
+    else if (!strcasecmp (s, "u16")) {
+        *defaultp = 0;
+        return AUD_FMT_U16;
+    }
+    else if (!strcasecmp (s, "s8")) {
+        *defaultp = 0;
+        return AUD_FMT_S8;
+    }
+    else if (!strcasecmp (s, "s16")) {
+        *defaultp = 0;
+        return AUD_FMT_S16;
+    }
+    else {
+        dolog ("Bogus audio format `%s' using %s\n",
+               s, audio_audfmt_to_string (defval));
+        *defaultp = 1;
+        return defval;
+    }
+}
+
+static audfmt_e audio_get_conf_fmt (const char *envname,
+                                    audfmt_e defval,
+                                    int *defaultp)
+{
+    const char *var = getenv (envname);
+    if (!var) {
+        *defaultp = 1;
+        return defval;
+    }
+    return audio_string_to_audfmt (var, defval, defaultp);
+}
+
+static int audio_get_conf_int (const char *key, int defval, int *defaultp)
+{
+    int val;
     char *strval;
 
     strval = getenv (key);
     if (strval) {
+        *defaultp = 0;
         val = atoi (strval);
+        return val;
+    }
+    else {
+        *defaultp = 1;
+        return defval;
     }
-
-    return val;
 }
 
-const char *audio_get_conf_str (const char *key, const char *defval)
+static const char *audio_get_conf_str (const char *key,
+                                       const char *defval,
+                                       int *defaultp)
 {
     const char *val = getenv (key);
-    if (!val)
+    if (!val) {
+        *defaultp = 1;
         return defval;
-    else
+    }
+    else {
+        *defaultp = 0;
         return val;
+    }
+}
+
+void AUD_vlog (const char *cap, const char *fmt, va_list ap)
+{
+    if (conf.log_to_monitor) {
+        if (cap) {
+            term_printf ("%s: ", cap);
+        }
+
+        term_vprintf (fmt, ap);
+    }
+    else {
+        if (cap) {
+            fprintf (stderr, "%s: ", cap);
+        }
+
+        vfprintf (stderr, fmt, ap);
+    }
 }
 
 void AUD_log (const char *cap, const char *fmt, ...)
 {
     va_list ap;
-    fprintf (stderr, "%s: ", cap);
+
     va_start (ap, fmt);
-    vfprintf (stderr, fmt, ap);
+    AUD_vlog (cap, fmt, ap);
     va_end (ap);
 }
 
-/*
- * Soft Voice
- */
-void pcm_sw_free_resources (SWVoice *sw)
+static void audio_print_options (const char *prefix,
+                                 struct audio_option *opt)
 {
-    if (sw->buf) qemu_free (sw->buf);
-    if (sw->rate) st_rate_stop (sw->rate);
-    sw->buf = NULL;
-    sw->rate = NULL;
+    char *uprefix;
+
+    if (!prefix) {
+        dolog ("No prefix specified\n");
+        return;
+    }
+
+    if (!opt) {
+        dolog ("No options\n");
+        return;
+    }
+
+    uprefix = audio_alloc_prefix (prefix);
+
+    for (; opt->name; opt++) {
+        const char *state = "default";
+        printf ("  %s_%s: ", uprefix, opt->name);
+
+        if (opt->overridenp && *opt->overridenp) {
+            state = "current";
+        }
+
+        switch (opt->tag) {
+        case AUD_OPT_BOOL:
+            {
+                int *intp = opt->valp;
+                printf ("boolean, %s = %d\n", state, *intp ? 1 : 0);
+            }
+            break;
+
+        case AUD_OPT_INT:
+            {
+                int *intp = opt->valp;
+                printf ("integer, %s = %d\n", state, *intp);
+            }
+            break;
+
+        case AUD_OPT_FMT:
+            {
+                audfmt_e *fmtp = opt->valp;
+                printf (
+                    "format, %s = %s, (one of: U8 S8 U16 S16)\n",
+                    state,
+                    audio_audfmt_to_string (*fmtp)
+                    );
+            }
+            break;
+
+        case AUD_OPT_STR:
+            {
+                const char **strp = opt->valp;
+                printf ("string, %s = %s\n",
+                        state,
+                        *strp ? *strp : "(not set)");
+            }
+            break;
+
+        default:
+            printf ("???\n");
+            dolog ("Bad value tag for option %s_%s %d\n",
+                   uprefix, opt->name, opt->tag);
+            break;
+        }
+        printf ("    %s\n", opt->descr);
+    }
+
+    qemu_free (uprefix);
 }
 
-int pcm_sw_alloc_resources (SWVoice *sw)
+static void audio_process_options (const char *prefix,
+                                   struct audio_option *opt)
 {
-    sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t));
-    if (!sw->buf)
-        return -1;
+    char *optname;
+    const char qemu_prefix[] = "QEMU_";
+    size_t preflen;
+
+    if (audio_bug (AUDIO_FUNC, !prefix)) {
+        dolog ("prefix = NULL\n");
+        return;
+    }
+
+    if (audio_bug (AUDIO_FUNC, !opt)) {
+        dolog ("opt = NULL\n");
+        return;
+    }
+
+    preflen = strlen (prefix);
+
+    for (; opt->name; opt++) {
+        size_t len, i;
+        int def;
+
+        if (!opt->valp) {
+            dolog ("Option value pointer for `%s' is not set\n",
+                   opt->name);
+            continue;
+        }
+
+        len = strlen (opt->name);
+        /* len of opt->name + len of prefix + size of qemu_prefix
+         * (includes trailing zero) + zero + underscore (on behalf of
+         * sizeof) */
+        optname = qemu_malloc (len + preflen + sizeof (qemu_prefix) + 1);
+        if (!optname) {
+            dolog ("Could not allocate memory for option name `%s'\n",
+                   opt->name);
+            continue;
+        }
+
+        strcpy (optname, qemu_prefix);
+
+        /* copy while upper-casing, including trailing zero */
+        for (i = 0; i <= preflen; ++i) {
+            optname[i + sizeof (qemu_prefix) - 1] = toupper (prefix[i]);
+        }
+        strcat (optname, "_");
+        strcat (optname, opt->name);
+
+        def = 1;
+        switch (opt->tag) {
+        case AUD_OPT_BOOL:
+        case AUD_OPT_INT:
+            {
+                int *intp = opt->valp;
+                *intp = audio_get_conf_int (optname, *intp, &def);
+            }
+            break;
+
+        case AUD_OPT_FMT:
+            {
+                audfmt_e *fmtp = opt->valp;
+                *fmtp = audio_get_conf_fmt (optname, *fmtp, &def);
+            }
+            break;
+
+        case AUD_OPT_STR:
+            {
+                const char **strp = opt->valp;
+                *strp = audio_get_conf_str (optname, *strp, &def);
+            }
+            break;
+
+        default:
+            dolog ("Bad value tag for option `%s' - %d\n",
+                   optname, opt->tag);
+            break;
+        }
+
+        if (!opt->overridenp) {
+            opt->overridenp = &opt->overriden;
+        }
+        *opt->overridenp = !def;
+        qemu_free (optname);
+    }
+}
+
+static void audio_print_settings (audsettings_t *as)
+{
+    dolog ("frequency=%d nchannels=%d fmt=", as->freq, as->nchannels);
+
+    switch (as->fmt) {
+    case AUD_FMT_S8:
+        AUD_log (NULL, "S8");
+        break;
+    case AUD_FMT_U8:
+        AUD_log (NULL, "U8");
+        break;
+    case AUD_FMT_S16:
+        AUD_log (NULL, "S16");
+        break;
+    case AUD_FMT_U16:
+        AUD_log (NULL, "U16");
+        break;
+    default:
+        AUD_log (NULL, "invalid(%d)", as->fmt);
+        break;
+    }
+    AUD_log (NULL, "\n");
+}
+
+static int audio_validate_settigs (audsettings_t *as)
+{
+    int invalid;
+
+    invalid = as->nchannels != 1 && as->nchannels != 2;
 
-    sw->rate = st_rate_start (sw->freq, sw->hw->freq);
-    if (!sw->rate) {
-        qemu_free (sw->buf);
-        sw->buf = NULL;
+    switch (as->fmt) {
+    case AUD_FMT_S8:
+    case AUD_FMT_U8:
+    case AUD_FMT_S16:
+    case AUD_FMT_U16:
+        break;
+    default:
+        invalid = 1;
+        break;
+    }
+
+    invalid |= as->freq <= 0;
+
+    if (invalid) {
         return -1;
     }
     return 0;
 }
 
-void pcm_sw_fini (SWVoice *sw)
+static int audio_pcm_info_eq (struct audio_pcm_info *info, audsettings_t *as)
 {
-    pcm_sw_free_resources (sw);
+    int bits = 8, sign = 0;
+
+    switch (as->fmt) {
+    case AUD_FMT_S8:
+        sign = 1;
+    case AUD_FMT_U8:
+        break;
+
+    case AUD_FMT_S16:
+        sign = 1;
+    case AUD_FMT_U16:
+        bits = 16;
+        break;
+    }
+    return info->freq == as->freq
+        && info->nchannels == as->nchannels
+        && info->sign == sign
+        && info->bits == bits;
 }
 
-int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
-                 int nchannels, audfmt_e fmt)
+void audio_pcm_init_info (
+    struct audio_pcm_info *info,
+    audsettings_t *as,
+    int swap_endian
+    )
 {
     int bits = 8, sign = 0;
 
-    switch (fmt) {
+    switch (as->fmt) {
     case AUD_FMT_S8:
         sign = 1;
     case AUD_FMT_U8:
@@ -148,764 +580,902 @@ int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
         break;
     }
 
-    sw->hw = hw;
-    sw->freq = freq;
-    sw->fmt = fmt;
-    sw->nchannels = nchannels;
-    sw->shift = (nchannels == 2) + (bits == 16);
-    sw->align = (1 << sw->shift) - 1;
-    sw->left = 0;
-    sw->pos = 0;
-    sw->wpos = 0;
-    sw->live = 0;
-    sw->ratio = (sw->hw->freq * ((int64_t) INT_MAX)) / sw->freq;
-    sw->bytes_per_second = sw->freq << sw->shift;
-    sw->conv = mixeng_conv[nchannels == 2][sign][bits == 16];
-
-    pcm_sw_free_resources (sw);
-    return pcm_sw_alloc_resources (sw);
+    info->freq = as->freq;
+    info->bits = bits;
+    info->sign = sign;
+    info->nchannels = as->nchannels;
+    info->shift = (as->nchannels == 2) + (bits == 16);
+    info->align = (1 << info->shift) - 1;
+    info->bytes_per_second = info->freq << info->shift;
+    info->swap_endian = swap_endian;
 }
 
-/* Hard voice */
-void pcm_hw_free_resources (HWVoice *hw)
+void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
 {
-    if (hw->mix_buf)
-        qemu_free (hw->mix_buf);
-    hw->mix_buf = NULL;
+    if (!len) {
+        return;
+    }
+
+    if (info->sign) {
+        memset (buf, len << info->shift, 0x00);
+    }
+    else {
+        if (info->bits == 8) {
+            memset (buf, len << info->shift, 0x80);
+        }
+        else {
+            int i;
+            uint16_t *p = buf;
+            int shift = info->nchannels - 1;
+            short s = INT16_MAX;
+
+            if (info->swap_endian) {
+                s = bswap16 (s);
+            }
+
+            for (i = 0; i < len << shift; i++) {
+                p[i] = s;
+            }
+        }
+    }
 }
 
-int pcm_hw_alloc_resources (HWVoice *hw)
+/*
+ * Hard voice (capture)
+ */
+static int audio_pcm_hw_find_min_in (HWVoiceIn *hw)
 {
-    hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t));
-    if (!hw->mix_buf)
-        return -1;
-    return 0;
+    SWVoiceIn *sw;
+    int m = hw->total_samples_captured;
+
+    for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+        if (sw->active) {
+            m = audio_MIN (m, sw->total_hw_samples_acquired);
+        }
+    }
+    return m;
 }
 
-void pcm_hw_fini (HWVoice *hw)
+int audio_pcm_hw_get_live_in (HWVoiceIn *hw)
 {
-    if (hw->active) {
-        ldebug ("pcm_hw_fini: %d %d %d\n", hw->freq, hw->nchannels, hw->fmt);
-        pcm_hw_free_resources (hw);
-        hw->pcm_ops->fini (hw);
-        memset (hw, 0, audio_state.drv->voice_size);
+    int live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
+    if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+        dolog ("live=%d hw->samples=%d\n", live, hw->samples);
+        return 0;
     }
+    return live;
 }
 
-void pcm_hw_gc (HWVoice *hw)
+/*
+ * Soft voice (capture)
+ */
+static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw)
 {
-    if (hw->nb_voices)
-        return;
+    HWVoiceIn *hw = sw->hw;
+    int live = hw->total_samples_captured - sw->total_hw_samples_acquired;
+    int rpos;
 
-    pcm_hw_fini (hw);
+    if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+        dolog ("live=%d hw->samples=%d\n", live, hw->samples);
+        return 0;
+    }
+
+    rpos = hw->wpos - live;
+    if (rpos >= 0) {
+        return rpos;
+    }
+    else {
+        return hw->samples + rpos;
+    }
 }
 
-int pcm_hw_get_live (HWVoice *hw)
+int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
 {
-    int i, alive = 0, live = hw->samples;
+    HWVoiceIn *hw = sw->hw;
+    int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
+    st_sample_t *src, *dst = sw->buf;
 
-    for (i = 0; i < hw->nb_voices; i++) {
-        if (hw->pvoice[i]->live) {
-            live = audio_MIN (hw->pvoice[i]->live, live);
-            alive += 1;
-        }
+    rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
+
+    live = hw->total_samples_captured - sw->total_hw_samples_acquired;
+    if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+        dolog ("live_in=%d hw->samples=%d\n", live, hw->samples);
+        return 0;
     }
 
-    if (alive)
-        return live;
-    else
-        return -1;
-}
+    samples = size >> sw->info.shift;
+    if (!live) {
+        return 0;
+    }
 
-int pcm_hw_get_live2 (HWVoice *hw, int *nb_active)
-{
-    int i, alive = 0, live = hw->samples;
+    swlim = (live * sw->ratio) >> 32;
+    swlim = audio_MIN (swlim, samples);
 
-    *nb_active = 0;
-    for (i = 0; i < hw->nb_voices; i++) {
-        if (hw->pvoice[i]->live) {
-            if (hw->pvoice[i]->live < live) {
-                *nb_active = hw->pvoice[i]->active != 0;
-                live = hw->pvoice[i]->live;
-            }
-            alive += 1;
+    while (swlim) {
+        src = hw->conv_buf + rpos;
+        isamp = hw->wpos - rpos;
+        /* XXX: <= ? */
+        if (isamp <= 0) {
+            isamp = hw->samples - rpos;
+        }
+
+        if (!isamp) {
+            break;
+        }
+        osamp = swlim;
+
+        if (audio_bug (AUDIO_FUNC, osamp < 0)) {
+            dolog ("osamp=%d\n", osamp);
+            return 0;
         }
+
+        st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
+        swlim -= osamp;
+        rpos = (rpos + isamp) % hw->samples;
+        dst += osamp;
+        ret += osamp;
+        total += isamp;
     }
 
-    if (alive)
-        return live;
-    else
-        return -1;
+    sw->clip (buf, sw->buf, ret);
+    sw->total_hw_samples_acquired += total;
+    return ret << sw->info.shift;
 }
 
-void pcm_hw_dec_live (HWVoice *hw, int decr)
+/*
+ * Hard voice (playback)
+ */
+static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep)
 {
-    int i;
-
-    for (i = 0; i < hw->nb_voices; i++) {
-        if (hw->pvoice[i]->live) {
-            hw->pvoice[i]->live -= decr;
+    SWVoiceOut *sw;
+    int m = INT_MAX;
+    int nb_live = 0;
+
+    for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+        if (sw->active || !sw->empty) {
+            m = audio_MIN (m, sw->total_hw_samples_mixed);
+            nb_live += 1;
         }
     }
+
+    *nb_livep = nb_live;
+    return m;
 }
 
-void pcm_hw_clear (HWVoice *hw, void *buf, int len)
+int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live)
 {
-    if (!len)
-        return;
+    int smin;
 
-    switch (hw->fmt) {
-    case AUD_FMT_S16:
-    case AUD_FMT_S8:
-        memset (buf, len << hw->shift, 0x00);
-        break;
-
-    case AUD_FMT_U8:
-        memset (buf, len << hw->shift, 0x80);
-        break;
+    smin = audio_pcm_hw_find_min_out (hw, nb_live);
 
-    case AUD_FMT_U16:
-        {
-            unsigned int i;
-            uint16_t *p = buf;
-            int shift = hw->nchannels - 1;
+    if (!*nb_live) {
+        return 0;
+    }
+    else {
+        int live = smin;
 
-            for (i = 0; i < len << shift; i++) {
-                p[i] = INT16_MAX;
-            }
+        if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+            dolog ("live=%d hw->samples=%d\n", live, hw->samples);
+            return 0;
         }
-        break;
+        return live;
     }
 }
 
-int pcm_hw_write (SWVoice *sw, void *buf, int size)
+int audio_pcm_hw_get_live_out (HWVoiceOut *hw)
+{
+    int nb_live;
+    int live;
+
+    live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
+    if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+        dolog ("live=%d hw->samples=%d\n", live, hw->samples);
+        return 0;
+    }
+    return live;
+}
+
+/*
+ * Soft voice (playback)
+ */
+int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
 {
     int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
-    int ret = 0, pos = 0;
-    if (!sw)
+    int ret = 0, pos = 0, total = 0;
+
+    if (!sw) {
         return size;
+    }
 
     hwsamples = sw->hw->samples;
-    samples = size >> sw->shift;
 
-    if (!sw->live) {
-        sw->wpos = sw->hw->rpos;
+    live = sw->total_hw_samples_mixed;
+    if (audio_bug (AUDIO_FUNC, live < 0 || live > hwsamples)){
+        dolog ("live=%d hw->samples=%d\n", live, hwsamples);
+        return 0;
     }
-    wpos = sw->wpos;
-    live = sw->live;
+
+    if (live == hwsamples) {
+        return 0;
+    }
+
+    wpos = (sw->hw->rpos + live) % hwsamples;
+    samples = size >> sw->info.shift;
+
     dead = hwsamples - live;
-    swlim = (dead * ((int64_t) INT_MAX)) / sw->ratio;
+    swlim = ((int64_t) dead << 32) / sw->ratio;
     swlim = audio_MIN (swlim, samples);
-
-    ldebug ("size=%d live=%d dead=%d swlim=%d wpos=%d\n",
-           size, live, dead, swlim, wpos);
-    if (swlim)
-        sw->conv (sw->buf, buf, swlim);
+    if (swlim) {
+        sw->conv (sw->buf, buf, swlim, &sw->vol);
+    }
 
     while (swlim) {
         dead = hwsamples - live;
         left = hwsamples - wpos;
         blck = audio_MIN (dead, left);
         if (!blck) {
-            /* dolog ("swlim=%d\n", swlim); */
             break;
         }
         isamp = swlim;
         osamp = blck;
-        st_rate_flow (sw->rate, sw->buf + pos, sw->hw->mix_buf + wpos, &isamp, &osamp);
+        st_rate_flow_mix (
+            sw->rate,
+            sw->buf + pos,
+            sw->hw->mix_buf + wpos,
+            &isamp,
+            &osamp
+            );
         ret += isamp;
         swlim -= isamp;
         pos += isamp;
         live += osamp;
-        wpos = (wpos + osamp) % hwsamples;
-    }
-
-    sw->wpos = wpos;
-    sw->live = live;
-    return ret << sw->shift;
-}
-
-int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
-{
-    int sign = 0, bits = 8;
-
-    pcm_hw_fini (hw);
-    ldebug ("pcm_hw_init: %d %d %d\n", freq, nchannels, fmt);
-    if (hw->pcm_ops->init (hw, freq, nchannels, fmt)) {
-        memset (hw, 0, audio_state.drv->voice_size);
-        return -1;
+        wpos = (wpos + osamp) % hwsamples;
+        total += osamp;
     }
 
-    switch (hw->fmt) {
-    case AUD_FMT_S8:
-        sign = 1;
-    case AUD_FMT_U8:
-        break;
-
-    case AUD_FMT_S16:
-        sign = 1;
-    case AUD_FMT_U16:
-        bits = 16;
-        break;
-    }
+    sw->total_hw_samples_mixed += total;
+    sw->empty = sw->total_hw_samples_mixed == 0;
+
+#ifdef DEBUG_OUT
+    dolog (
+        "%s: write size %d ret %d total sw %d\n",
+        SW_NAME (sw),
+        size >> sw->info.shift,
+        ret,
+        sw->total_hw_samples_mixed
+        );
+#endif
 
-    hw->nb_voices = 0;
-    hw->active = 1;
-    hw->shift = (hw->nchannels == 2) + (bits == 16);
-    hw->bytes_per_second = hw->freq << hw->shift;
-    hw->align = (1 << hw->shift) - 1;
-    hw->samples = hw->bufsize >> hw->shift;
-    hw->clip = mixeng_clip[hw->nchannels == 2][sign][bits == 16];
-    if (pcm_hw_alloc_resources (hw)) {
-        pcm_hw_fini (hw);
-        return -1;
-    }
-    return 0;
+    return ret << sw->info.shift;
 }
 
-static int dist (void *hw)
+#ifdef DEBUG_AUDIO
+static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
 {
-    if (hw) {
-        return (((uint8_t *) hw - (uint8_t *) hw_voices)
-                / audio_state.drv->voice_size) + 1;
-    }
-    else {
-        return 0;
-    }
+    dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n",
+           cap, info->bits, info->sign, info->freq, info->nchannels);
 }
+#endif
 
-#define ADVANCE(hw) \
-    ((hw) ? advance (hw, audio_state.drv->voice_size) : hw_voices)
+#define DAC
+#include "audio_template.h"
+#undef DAC
+#include "audio_template.h"
 
-HWVoice *pcm_hw_find_any (HWVoice *hw)
+int AUD_write (SWVoiceOut *sw, void *buf, int size)
 {
-    int i = dist (hw);
-    for (; i < audio_state.nb_hw_voices; i++) {
-        hw = ADVANCE (hw);
-        return hw;
+    int bytes;
+
+    if (!sw) {
+        /* XXX: Consider options */
+        return size;
     }
-    return NULL;
-}
 
-HWVoice *pcm_hw_find_any_active (HWVoice *hw)
-{
-    int i = dist (hw);
-    for (; i < audio_state.nb_hw_voices; i++) {
-        hw = ADVANCE (hw);
-        if (hw->active)
-            return hw;
+    if (!sw->hw->enabled) {
+        dolog ("Writing to disabled voice %s\n", SW_NAME (sw));
+        return 0;
     }
-    return NULL;
+
+    bytes = sw->hw->pcm_ops->write (sw, buf, size);
+    return bytes;
 }
 
-HWVoice *pcm_hw_find_any_active_enabled (HWVoice *hw)
+int AUD_read (SWVoiceIn *sw, void *buf, int size)
 {
-    int i = dist (hw);
-    for (; i < audio_state.nb_hw_voices; i++) {
-        hw = ADVANCE (hw);
-        if (hw->active && hw->enabled)
-            return hw;
+    int bytes;
+
+    if (!sw) {
+        /* XXX: Consider options */
+        return size;
     }
-    return NULL;
-}
 
-HWVoice *pcm_hw_find_any_passive (HWVoice *hw)
-{
-    int i = dist (hw);
-    for (; i < audio_state.nb_hw_voices; i++) {
-        hw = ADVANCE (hw);
-        if (!hw->active)
-            return hw;
+    if (!sw->hw->enabled) {
+        dolog ("Reading from disabled voice %s\n", SW_NAME (sw));
+        return 0;
     }
-    return NULL;
+
+    bytes = sw->hw->pcm_ops->read (sw, buf, size);
+    return bytes;
 }
 
-HWVoice *pcm_hw_find_specific (HWVoice *hw, int freq,
-                               int nchannels, audfmt_e fmt)
+int AUD_get_buffer_size_out (SWVoiceOut *sw)
 {
-    while ((hw = pcm_hw_find_any_active (hw))) {
-        if (hw->freq == freq &&
-            hw->nchannels == nchannels &&
-            hw->fmt == fmt)
-            return hw;
-    }
-    return NULL;
+    return sw->hw->samples << sw->hw->info.shift;
 }
 
-HWVoice *pcm_hw_add (int freq, int nchannels, audfmt_e fmt)
+void AUD_set_active_out (SWVoiceOut *sw, int on)
 {
-    HWVoice *hw;
+    HWVoiceOut *hw;
 
-    if (audio_state.fixed_format) {
-        freq = audio_state.fixed_freq;
-        nchannels = audio_state.fixed_channels;
-        fmt = audio_state.fixed_fmt;
+    if (!sw) {
+        return;
     }
 
-    hw = pcm_hw_find_specific (NULL, freq, nchannels, fmt);
+    hw = sw->hw;
+    if (sw->active != on) {
+        SWVoiceOut *temp_sw;
+
+        if (on) {
+            int total;
+
+            hw->pending_disable = 0;
+            if (!hw->enabled) {
+                hw->enabled = 1;
+                hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
+            }
 
-    if (hw)
-        return hw;
+            if (sw->empty) {
+                total = 0;
+            }
+        }
+        else {
+            if (hw->enabled) {
+                int nb_active = 0;
 
-    hw = pcm_hw_find_any_passive (NULL);
-    if (hw) {
-        hw->pcm_ops = audio_state.drv->pcm_ops;
-        if (!hw->pcm_ops)
-            return NULL;
+                for (temp_sw = hw->sw_head.lh_first; temp_sw;
+                     temp_sw = temp_sw->entries.le_next) {
+                    nb_active += temp_sw->active != 0;
+                }
 
-        if (pcm_hw_init (hw, freq, nchannels, fmt)) {
-            pcm_hw_gc (hw);
-            return NULL;
+                hw->pending_disable = nb_active == 1;
+            }
         }
-        else
-            return hw;
+        sw->active = on;
     }
-
-    return pcm_hw_find_any (NULL);
 }
 
-int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw)
+void AUD_set_active_in (SWVoiceIn *sw, int on)
 {
-    SWVoice **pvoice = qemu_mallocz ((hw->nb_voices + 1) * sizeof (sw));
-    if (!pvoice)
-        return -1;
+    HWVoiceIn *hw;
 
-    memcpy (pvoice, hw->pvoice, hw->nb_voices * sizeof (sw));
-    qemu_free (hw->pvoice);
-    hw->pvoice = pvoice;
-    hw->pvoice[hw->nb_voices++] = sw;
-    return 0;
-}
+    if (!sw) {
+        return;
+    }
 
-int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw)
-{
-    int i, j;
-    if (hw->nb_voices > 1) {
-        SWVoice **pvoice = qemu_mallocz ((hw->nb_voices - 1) * sizeof (sw));
+    hw = sw->hw;
+    if (sw->active != on) {
+        SWVoiceIn *temp_sw;
 
-        if (!pvoice) {
-            dolog ("Can not maintain consistent state (not enough memory)\n");
-            return -1;
+        if (on) {
+            if (!hw->enabled) {
+                hw->enabled = 1;
+                hw->pcm_ops->ctl_in (hw, VOICE_ENABLE);
+            }
+            sw->total_hw_samples_acquired = hw->total_samples_captured;
         }
+        else {
+            if (hw->enabled) {
+                int nb_active = 0;
+
+                for (temp_sw = hw->sw_head.lh_first; temp_sw;
+                     temp_sw = temp_sw->entries.le_next) {
+                    nb_active += temp_sw->active != 0;
+                }
 
-        for (i = 0, j = 0; i < hw->nb_voices; i++) {
-            if (j >= hw->nb_voices - 1) {
-                dolog ("Can not maintain consistent state "
-                       "(invariant violated)\n");
-                return -1;
+                if (nb_active == 1) {
+                    hw->enabled = 0;
+                    hw->pcm_ops->ctl_in (hw, VOICE_DISABLE);
+                }
             }
-            if (hw->pvoice[i] != sw)
-                pvoice[j++] = hw->pvoice[i];
         }
-        qemu_free (hw->pvoice);
-        hw->pvoice = pvoice;
-        hw->nb_voices -= 1;
-    }
-    else {
-        qemu_free (hw->pvoice);
-        hw->pvoice = NULL;
-        hw->nb_voices = 0;
+        sw->active = on;
     }
-    return 0;
 }
 
-SWVoice *pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt)
+static int audio_get_avail (SWVoiceIn *sw)
 {
-    SWVoice *sw;
-    HWVoice *hw;
-
-    sw = qemu_mallocz (sizeof (*sw));
-    if (!sw)
-        goto err1;
+    int live;
 
-    hw = pcm_hw_add (freq, nchannels, fmt);
-    if (!hw)
-        goto err2;
-
-    if (pcm_hw_add_sw (hw, sw))
-        goto err3;
+    if (!sw) {
+        return 0;
+    }
 
-    if (pcm_sw_init (sw, hw, freq, nchannels, fmt))
-        goto err4;
+    live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
+    if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
+        dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
+        return 0;
+    }
 
-    return sw;
+    ldebug (
+        "%s: get_avail live %d ret %lld\n",
+        SW_NAME (sw),
+        live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift
+        );
 
-err4:
-    pcm_hw_del_sw (hw, sw);
-err3:
-    pcm_hw_gc (hw);
-err2:
-    qemu_free (sw);
-err1:
-    return NULL;
+    return (((int64_t) live << 32) / sw->ratio) << sw->info.shift;
 }
 
-SWVoice *AUD_open (SWVoice *sw, const char *name,
-                   int freq, int nchannels, audfmt_e fmt)
+static int audio_get_free (SWVoiceOut *sw)
 {
-    if (!audio_state.drv) {
-        return NULL;
-    }
+    int live, dead;
 
-    if (sw && freq == sw->freq && sw->nchannels == nchannels && sw->fmt == fmt) {
-        return sw;
+    if (!sw) {
+        return 0;
     }
 
-    if (sw) {
-        ldebug ("Different format %s %d %d %d\n",
-                name,
-                sw->freq == freq,
-                sw->nchannels == nchannels,
-                sw->fmt == fmt);
-    }
+    live = sw->total_hw_samples_mixed;
 
-    if (nchannels != 1 && nchannels != 2) {
-        dolog ("Bogus channel count %d for voice %s\n", nchannels, name);
-        return NULL;
+    if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
+        dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
+        return 0;
     }
 
-    if (!audio_state.fixed_format && sw) {
-        pcm_sw_fini (sw);
-        pcm_hw_del_sw (sw->hw, sw);
-        pcm_hw_gc (sw->hw);
-        if (sw->name) {
-            qemu_free (sw->name);
-            sw->name = NULL;
+    dead = sw->hw->samples - live;
+
+#ifdef DEBUG_OUT
+    dolog ("%s: get_free live %d dead %d ret %lld\n",
+           SW_NAME (sw),
+           live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift);
+#endif
+
+    return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;
+}
+
+static void audio_run_out (AudioState *s)
+{
+    HWVoiceOut *hw = NULL;
+    SWVoiceOut *sw;
+
+    while ((hw = audio_pcm_hw_find_any_enabled_out (s, hw))) {
+        int played;
+        int live, free, nb_live, cleanup_required;
+
+        live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
+        if (!nb_live) {
+            live = 0;
         }
-        qemu_free (sw);
-        sw = NULL;
-    }
 
-    if (sw) {
-        HWVoice *hw = sw->hw;
-        if (!hw) {
-            dolog ("Internal logic error voice %s has no hardware store\n",
-                   name);
-            return sw;
+        if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
+            dolog ("live=%d hw->samples=%d\n", live, hw->samples);
+            continue;
+        }
+
+        if (hw->pending_disable && !nb_live) {
+#ifdef DEBUG_OUT
+            dolog ("Disabling voice\n");
+#endif
+            hw->enabled = 0;
+            hw->pending_disable = 0;
+            hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
+            continue;
         }
 
-        if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) {
-            pcm_sw_fini (sw);
-            pcm_hw_del_sw (hw, sw);
-            pcm_hw_gc (hw);
-            if (sw->name) {
-                qemu_free (sw->name);
-                sw->name = NULL;
+        if (!live) {
+            for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+                if (sw->active) {
+                    free = audio_get_free (sw);
+                    if (free > 0) {
+                        sw->callback.fn (sw->callback.opaque, free);
+                    }
+                }
             }
-            qemu_free (sw);
-            return NULL;
+            continue;
         }
-    }
-    else {
-        sw = pcm_create_voice_pair (freq, nchannels, fmt);
-        if (!sw) {
-            dolog ("Failed to create voice %s\n", name);
-            return NULL;
+
+        played = hw->pcm_ops->run_out (hw);
+        if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
+            dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
+                   hw->rpos, hw->samples, played);
+            hw->rpos = 0;
         }
-    }
 
-    if (sw->name) {
-        qemu_free (sw->name);
-        sw->name = NULL;
-    }
-    sw->name = qemu_strdup (name);
-    return sw;
-}
+#ifdef DEBUG_OUT
+        dolog ("played=%d\n", played);
+#endif
 
-void AUD_close (SWVoice *sw)
-{
-    if (!sw)
-        return;
+        if (played) {
+            hw->ts_helper += played;
+        }
 
-    pcm_sw_fini (sw);
-    pcm_hw_del_sw (sw->hw, sw);
-    pcm_hw_gc (sw->hw);
-    if (sw->name) {
-        qemu_free (sw->name);
-        sw->name = NULL;
-    }
-    qemu_free (sw);
-}
+        cleanup_required = 0;
+        for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+            if (!sw->active && sw->empty) {
+                continue;
+            }
 
-int AUD_write (SWVoice *sw, void *buf, int size)
-{
-    int bytes;
+            if (audio_bug (AUDIO_FUNC, played > sw->total_hw_samples_mixed)) {
+                dolog ("played=%d sw->total_hw_samples_mixed=%d\n",
+                       played, sw->total_hw_samples_mixed);
+                played = sw->total_hw_samples_mixed;
+            }
 
-    if (!sw->hw->enabled)
-        dolog ("Writing to disabled voice %s\n", sw->name);
-    bytes = sw->hw->pcm_ops->write (sw, buf, size);
-    return bytes;
-}
+            sw->total_hw_samples_mixed -= played;
 
-void AUD_run (void)
-{
-    HWVoice *hw = NULL;
+            if (!sw->total_hw_samples_mixed) {
+                sw->empty = 1;
+                cleanup_required |= !sw->active && !sw->callback.fn;
+            }
 
-    while ((hw = pcm_hw_find_any_active_enabled (hw))) {
-        int i;
-        if (hw->pending_disable && pcm_hw_get_live (hw) <= 0) {
-            hw->enabled = 0;
-            hw->pcm_ops->ctl (hw, VOICE_DISABLE);
-            for (i = 0; i < hw->nb_voices; i++) {
-                hw->pvoice[i]->live = 0;
-                /* hw->pvoice[i]->old_ticks = 0; */
+            if (sw->active) {
+                free = audio_get_free (sw);
+                if (free > 0) {
+                    sw->callback.fn (sw->callback.opaque, free);
+                }
             }
-            continue;
         }
 
-        hw->pcm_ops->run (hw);
-        assert (hw->rpos < hw->samples);
-        for (i = 0; i < hw->nb_voices; i++) {
-            SWVoice *sw = hw->pvoice[i];
-            if (!sw->active && !sw->live && sw->old_ticks) {
-                int64_t delta = qemu_get_clock (vm_clock) - sw->old_ticks;
-                if (delta > audio_state.ticks_threshold) {
-                    ldebug ("resetting old_ticks for %s\n", sw->name);
-                    sw->old_ticks = 0;
+        if (cleanup_required) {
+        restart:
+            for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+                if (!sw->active && !sw->callback.fn) {
+#ifdef DEBUG_PLIVE
+                    dolog ("Finishing with old voice\n");
+#endif
+                    audio_close_out (s, sw);
+                    goto restart; /* play it safe */
                 }
             }
         }
     }
 }
 
-int AUD_get_free (SWVoice *sw)
+static void audio_run_in (AudioState *s)
 {
-    int free;
+    HWVoiceIn *hw = NULL;
 
-    if (!sw)
-        return 4096;
+    while ((hw = audio_pcm_hw_find_any_enabled_in (s, hw))) {
+        SWVoiceIn *sw;
+        int captured, min;
 
-    free = ((sw->hw->samples - sw->live) << sw->hw->shift) * sw->ratio
-        / INT_MAX;
+        captured = hw->pcm_ops->run_in (hw);
 
-    free &= ~sw->hw->align;
-    if (!free) return 0;
+        min = audio_pcm_hw_find_min_in (hw);
+        hw->total_samples_captured += captured - min;
+        hw->ts_helper += captured;
 
-    return free;
-}
+        for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
+            sw->total_hw_samples_acquired -= min;
 
-int AUD_get_buffer_size (SWVoice *sw)
-{
-    return sw->hw->bufsize;
-}
+            if (sw->active) {
+                int avail;
 
-void AUD_adjust (SWVoice *sw, int bytes)
-{
-    if (!sw)
-        return;
-    sw->old_ticks += (ticks_per_sec * (int64_t) bytes) / sw->bytes_per_second;
+                avail = audio_get_avail (sw);
+                if (avail > 0) {
+                    sw->callback.fn (sw->callback.opaque, avail);
+                }
+            }
+        }
+    }
 }
 
-void AUD_reset (SWVoice *sw)
+static void audio_timer (void *opaque)
 {
-    sw->active = 0;
-    sw->old_ticks = 0;
+    AudioState *s = opaque;
+
+    audio_run_out (s);
+    audio_run_in (s);
+
+    qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
 }
 
-int AUD_calc_elapsed (SWVoice *sw)
-{
-    int64_t now, delta, bytes;
-    int dead, swlim;
+static struct audio_option audio_options[] = {
+    /* DAC */
+    {"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_out.enabled,
+     "Use fixed settings for host DAC", NULL, 0},
 
-    if (!sw)
-        return 0;
+    {"DAC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_out.settings.freq,
+     "Frequency for fixed host DAC", NULL, 0},
 
-    now = qemu_get_clock (vm_clock);
-    delta = now - sw->old_ticks;
-    bytes = (delta * sw->bytes_per_second) / ticks_per_sec;
-    if (delta < 0) {
-        dolog ("whoops delta(<0)=%lld\n", delta);
-        return 0;
-    }
+    {"DAC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_out.settings.fmt,
+     "Format for fixed host DAC", NULL, 0},
 
-    dead = sw->hw->samples - sw->live;
-    swlim = ((dead * (int64_t) INT_MAX) / sw->ratio);
+    {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_out.settings.nchannels,
+     "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0},
 
-    if (bytes > swlim) {
-        return swlim;
-    }
-    else {
-        return bytes;
+    {"DAC_VOICES", AUD_OPT_INT, &conf.fixed_out.nb_voices,
+     "Number of voices for DAC", NULL, 0},
+
+    /* ADC */
+    {"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_in.enabled,
+     "Use fixed settings for host ADC", NULL, 0},
+
+    {"ADC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_in.settings.freq,
+     "Frequency for fixed host ADC", NULL, 0},
+
+    {"ADC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_in.settings.fmt,
+     "Format for fixed host ADC", NULL, 0},
+
+    {"ADC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_in.settings.nchannels,
+     "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0},
+
+    {"ADC_VOICES", AUD_OPT_INT, &conf.fixed_in.nb_voices,
+     "Number of voices for ADC", NULL, 0},
+
+    /* Misc */
+    {"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hz,
+     "Timer period in HZ (0 - use lowest possible)", NULL, 0},
+
+    {"PLIVE", AUD_OPT_BOOL, &conf.plive,
+     "(undocumented)", NULL, 0},
+
+    {"LOG_TO_MONITOR", AUD_OPT_BOOL, &conf.log_to_monitor,
+     "print logging messages to montior instead of stderr", NULL, 0},
+
+    {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+static void audio_pp_nb_voices (const char *typ, int nb)
+{
+    switch (nb) {
+    case 0:
+        printf ("Does not support %s\n", typ);
+        break;
+    case 1:
+        printf ("One %s voice\n", typ);
+        break;
+    case INT_MAX:
+        printf ("Theoretically supports many %s voices\n", typ);
+        break;
+    default:
+        printf ("Theoretically supports upto %d %s voices\n", nb, typ);
+        break;
     }
+
 }
 
-void AUD_enable (SWVoice *sw, int on)
+void AUD_help (void)
 {
-    int i;
-    HWVoice *hw;
+    size_t i;
 
-    if (!sw)
-        return;
-
-    hw = sw->hw;
-    if (on) {
-        if (!sw->live)
-            sw->wpos = sw->hw->rpos;
-        if (!sw->old_ticks) {
-            sw->old_ticks = qemu_get_clock (vm_clock);
+    audio_process_options ("AUDIO", audio_options);
+    for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+        struct audio_driver *d = drvtab[i];
+        if (d->options) {
+            audio_process_options (d->name, d->options);
         }
     }
 
-    if (sw->active != on) {
-        if (on) {
-            hw->pending_disable = 0;
-            if (!hw->enabled) {
-                hw->enabled = 1;
-                for (i = 0; i < hw->nb_voices; i++) {
-                    ldebug ("resetting voice\n");
-                    sw = hw->pvoice[i];
-                    sw->old_ticks = qemu_get_clock (vm_clock);
-                }
-                hw->pcm_ops->ctl (hw, VOICE_ENABLE);
-            }
+    printf ("Audio options:\n");
+    audio_print_options ("AUDIO", audio_options);
+    printf ("\n");
+
+    printf ("Available drivers:\n");
+
+    for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+        struct audio_driver *d = drvtab[i];
+
+        printf ("Name: %s\n", d->name);
+        printf ("Description: %s\n", d->descr);
+
+        audio_pp_nb_voices ("playback", d->max_voices_out);
+        audio_pp_nb_voices ("capture", d->max_voices_in);
+
+        if (d->options) {
+            printf ("Options:\n");
+            audio_print_options (d->name, d->options);
         }
         else {
-            if (hw->enabled && !hw->pending_disable) {
-                int nb_active = 0;
-                for (i = 0; i < hw->nb_voices; i++) {
-                    nb_active += hw->pvoice[i]->active != 0;
-                }
-
-                if (nb_active == 1) {
-                    hw->pending_disable = 1;
-                }
-            }
+            printf ("No options\n");
         }
-        sw->active = on;
+        printf ("\n");
     }
-}
 
-static struct audio_output_driver *drvtab[] = {
-#ifdef CONFIG_OSS
-    &oss_output_driver,
-#endif
-#ifdef CONFIG_FMOD
-    &fmod_output_driver,
-#endif
-#ifdef CONFIG_SDL
-    &sdl_output_driver,
-#endif
-    &no_output_driver,
-#ifdef USE_WAV_AUDIO
-    &wav_output_driver,
+    printf (
+        "Options are settable through environment variables.\n"
+        "Example:\n"
+#ifdef _WIN32
+        "  set QEMU_AUDIO_DRV=wav\n"
+        "  set QEMU_WAV_PATH=c:\\tune.wav\n"
+#else
+        "  export QEMU_AUDIO_DRV=wav\n"
+        "  export QEMU_WAV_PATH=$HOME/tune.wav\n"
+        "(for csh replace export with setenv in the above)\n"
 #endif
-};
+        "  qemu ...\n\n"
+        );
+}
 
-static int voice_init (struct audio_output_driver *drv)
+static int audio_driver_init (AudioState *s, struct audio_driver *drv)
 {
-    audio_state.opaque = drv->init ();
-    if (audio_state.opaque) {
-        if (audio_state.nb_hw_voices > drv->max_voices) {
-            dolog ("`%s' does not support %d multiple hardware channels\n"
-                   "Resetting to %d\n",
-                   drv->name, audio_state.nb_hw_voices, drv->max_voices);
-            audio_state.nb_hw_voices = drv->max_voices;
-        }
-        hw_voices = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size);
-        if (hw_voices) {
-            audio_state.drv = drv;
-            return 1;
-        }
-        else {
-            dolog ("Not enough memory for %d `%s' voices (each %d bytes)\n",
-                   audio_state.nb_hw_voices, drv->name, drv->voice_size);
-            drv->fini (audio_state.opaque);
-            return 0;
-        }
+    if (drv->options) {
+        audio_process_options (drv->name, drv->options);
     }
-    else {
-        dolog ("Could not init `%s' audio\n", drv->name);
+    s->drv_opaque = drv->init ();
+
+    if (s->drv_opaque) {
+        audio_init_nb_voices_out (s, drv);
+        audio_init_nb_voices_in (s, drv);
+        s->drv = drv;
         return 0;
     }
+    else {
+        dolog ("Could not init `%s' audio driver\n", drv->name);
+        return -1;
+    }
 }
 
-static void audio_vm_stop_handler (void *opaque, int reason)
+static void audio_vm_change_state_handler (void *opaque, int running)
 {
-    HWVoice *hw = NULL;
+    AudioState *s = opaque;
+    HWVoiceOut *hwo = NULL;
+    HWVoiceIn *hwi = NULL;
+    int op = running ? VOICE_ENABLE : VOICE_DISABLE;
 
-    while ((hw = pcm_hw_find_any (hw))) {
-        if (!hw->pcm_ops)
-            continue;
+    while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
+        hwo->pcm_ops->ctl_out (hwo, op);
+    }
 
-        hw->pcm_ops->ctl (hw, reason ? VOICE_ENABLE : VOICE_DISABLE);
+    while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
+        hwi->pcm_ops->ctl_in (hwi, op);
     }
 }
 
 static void audio_atexit (void)
 {
-    HWVoice *hw = NULL;
+    AudioState *s = &glob_audio_state;
+    HWVoiceOut *hwo = NULL;
+    HWVoiceIn *hwi = NULL;
 
-    while ((hw = pcm_hw_find_any (hw))) {
-        if (!hw->pcm_ops)
-            continue;
+    while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
+        hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
+        hwo->pcm_ops->fini_out (hwo);
+    }
+
+    while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
+        hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
+        hwi->pcm_ops->fini_in (hwi);
+    }
 
-        hw->pcm_ops->ctl (hw, VOICE_DISABLE);
-        hw->pcm_ops->fini (hw);
+    if (s->drv) {
+        s->drv->fini (s->drv_opaque);
     }
-    audio_state.drv->fini (audio_state.opaque);
 }
 
 static void audio_save (QEMUFile *f, void *opaque)
 {
+    (void) f;
+    (void) opaque;
 }
 
 static int audio_load (QEMUFile *f, void *opaque, int version_id)
 {
-    if (version_id != 1)
+    (void) f;
+    (void) opaque;
+
+    if (version_id != 1) {
         return -EINVAL;
+    }
 
     return 0;
 }
 
-void AUD_init (void)
+void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card)
+{
+    card->audio = s;
+    card->name = qemu_strdup (name);
+    memset (&card->entries, 0, sizeof (card->entries));
+    LIST_INSERT_HEAD (&s->card_head, card, entries);
+}
+
+void AUD_remove_card (QEMUSoundCard *card)
+{
+    LIST_REMOVE (card, entries);
+    card->audio = NULL;
+    qemu_free (card->name);
+}
+
+AudioState *AUD_init (void)
 {
-    int i;
+    size_t i;
     int done = 0;
     const char *drvname;
+    AudioState *s = &glob_audio_state;
 
-    audio_state.fixed_format =
-        !!audio_get_conf_int (QC_FIXED_FORMAT, audio_state.fixed_format);
-    audio_state.fixed_freq =
-        audio_get_conf_int (QC_FIXED_FREQ, audio_state.fixed_freq);
-    audio_state.nb_hw_voices =
-        audio_get_conf_int (QC_VOICES, audio_state.nb_hw_voices);
+    LIST_INIT (&s->hw_head_out);
+    LIST_INIT (&s->hw_head_in);
+    atexit (audio_atexit);
+
+    s->ts = qemu_new_timer (vm_clock, audio_timer, s);
+    if (!s->ts) {
+        dolog ("Could not create audio timer\n");
+        return NULL;
+    }
+
+    audio_process_options ("AUDIO", audio_options);
+
+    s->nb_hw_voices_out = conf.fixed_out.nb_voices;
+    s->nb_hw_voices_in = conf.fixed_in.nb_voices;
+
+    if (s->nb_hw_voices_out <= 0) {
+        dolog ("Bogus number of playback voices %d, setting to 1\n",
+               s->nb_hw_voices_out);
+        s->nb_hw_voices_out = 1;
+    }
 
-    if (audio_state.nb_hw_voices <= 0) {
-        dolog ("Bogus number of voices %d, resetting to 1\n",
-               audio_state.nb_hw_voices);
+    if (s->nb_hw_voices_in <= 0) {
+        dolog ("Bogus number of capture voices %d, setting to 0\n",
+               s->nb_hw_voices_in);
+        s->nb_hw_voices_in = 0;
+    }
+
+    {
+        int def;
+        drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def);
     }
 
-    drvname = audio_get_conf_str (QC_AUDIO_DRV, NULL);
     if (drvname) {
         int found = 0;
+
         for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
             if (!strcmp (drvname, drvtab[i]->name)) {
-                done = voice_init (drvtab[i]);
+                done = !audio_driver_init (s, drvtab[i]);
                 found = 1;
                 break;
             }
         }
+
         if (!found) {
             dolog ("Unknown audio driver `%s'\n", drvname);
+            dolog ("Run with -audio-help to list available drivers\n");
         }
     }
 
-    qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL);
-    atexit (audio_atexit);
-
     if (!done) {
         for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
-            if (drvtab[i]->can_be_default)
-                done = voice_init (drvtab[i]);
+            if (drvtab[i]->can_be_default) {
+                done = !audio_driver_init (s, drvtab[i]);
+            }
         }
     }
 
-    audio_state.ticks_threshold = ticks_per_sec / 50;
-    audio_state.freq_threshold = 100;
-
-    register_savevm ("audio", 0, 1, audio_save, audio_load, NULL);
     if (!done) {
-        dolog ("Can not initialize audio subsystem\n");
-        voice_init (&no_output_driver);
+        done = !audio_driver_init (s, &no_audio_driver);
+        if (!done) {
+            dolog ("Could not initialize audio subsystem\n");
+        }
+        else {
+            dolog ("warning: Using timer based audio emulation\n");
+        }
+    }
+
+    if (done) {
+        VMChangeStateEntry *e;
+
+        if (conf.period.hz <= 0) {
+            if (conf.period.hz < 0) {
+                dolog ("warning: Timer period is negative - %d "
+                       "treating as zero\n",
+                       conf.period.hz);
+            }
+            conf.period.ticks = 1;
+        }
+        else {
+            conf.period.ticks = ticks_per_sec / conf.period.hz;
+        }
+
+        e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s);
+        if (!e) {
+            dolog ("warning: Could not register change state handler\n"
+                   "(Audio can continue looping even after stopping the VM)\n");
+        }
     }
+    else {
+        qemu_del_timer (s->ts);
+        return NULL;
+    }
+
+    LIST_INIT (&s->card_head);
+    register_savevm ("audio", 0, 1, audio_save, audio_load, s);
+    qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
+    return s;
 }
index 7520383..169b5f6 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * QEMU Audio subsystem header
- * 
- * Copyright (c) 2003-2004 Vassili Karpov (malc)
- * 
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
  * 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
 #ifndef QEMU_AUDIO_H
 #define QEMU_AUDIO_H
 
-#include "mixeng.h"
+#include "sys-queue.h"
+
+typedef void (*audio_callback_fn_t) (void *opaque, int avail);
 
 typedef enum {
-  AUD_FMT_U8,
-  AUD_FMT_S8,
-  AUD_FMT_U16,
-  AUD_FMT_S16
+    AUD_FMT_U8,
+    AUD_FMT_S8,
+    AUD_FMT_U16,
+    AUD_FMT_S16
 } audfmt_e;
 
-typedef struct SWVoice SWVoice;
-
-SWVoice * AUD_open (SWVoice *sw, const char *name, int freq,
-                    int nchannels, audfmt_e fmt);
-void   AUD_init (void);
-void   AUD_log (const char *cap, const char *fmt, ...)
-    __attribute__ ((__format__ (__printf__, 2, 3)));;
-void   AUD_close (SWVoice *sw);
-int    AUD_write (SWVoice *sw, void *pcm_buf, int size);
-void   AUD_adjust (SWVoice *sw, int leftover);
-void   AUD_reset (SWVoice *sw);
-int    AUD_get_free (SWVoice *sw);
-int    AUD_get_buffer_size (SWVoice *sw);
-void   AUD_run (void);
-void   AUD_enable (SWVoice *sw, int on);
-int    AUD_calc_elapsed (SWVoice *sw);
+typedef struct {
+    int freq;
+    int nchannels;
+    audfmt_e fmt;
+} audsettings_t;
+
+typedef struct AudioState AudioState;
+typedef struct SWVoiceOut SWVoiceOut;
+typedef struct SWVoiceIn SWVoiceIn;
+
+typedef struct QEMUSoundCard {
+    AudioState *audio;
+    char *name;
+    LIST_ENTRY (QEMUSoundCard) entries;
+} QEMUSoundCard;
+
+typedef struct QEMUAudioTimeStamp {
+    uint64_t old_ts;
+} QEMUAudioTimeStamp;
+
+void AUD_vlog (const char *cap, const char *fmt, va_list ap);
+void AUD_log (const char *cap, const char *fmt, ...)
+#ifdef __GNUC__
+    __attribute__ ((__format__ (__printf__, 2, 3)))
+#endif
+    ;
+
+AudioState *AUD_init (void);
+void AUD_help (void);
+void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card);
+void AUD_remove_card (QEMUSoundCard *card);
+
+SWVoiceOut *AUD_open_out (
+    QEMUSoundCard *card,
+    SWVoiceOut *sw,
+    const char *name,
+    void *callback_opaque,
+    audio_callback_fn_t callback_fn,
+    audsettings_t *settings,
+    int sw_endian
+    );
+
+void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw);
+int  AUD_write (SWVoiceOut *sw, void *pcm_buf, int size);
+int  AUD_get_buffer_size_out (SWVoiceOut *sw);
+void AUD_set_active_out (SWVoiceOut *sw, int on);
+int  AUD_is_active_out (SWVoiceOut *sw);
+
+void     AUD_init_time_stamp_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts);
+uint64_t AUD_get_elapsed_usec_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts);
+
+SWVoiceIn *AUD_open_in (
+    QEMUSoundCard *card,
+    SWVoiceIn *sw,
+    const char *name,
+    void *callback_opaque,
+    audio_callback_fn_t callback_fn,
+    audsettings_t *settings,
+    int sw_endian
+    );
+
+void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw);
+int  AUD_read (SWVoiceIn *sw, void *pcm_buf, int size);
+void AUD_set_active_in (SWVoiceIn *sw, int on);
+int  AUD_is_active_in (SWVoiceIn *sw);
+
+void     AUD_init_time_stamp_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts);
+uint64_t AUD_get_elapsed_usec_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts);
 
 static inline void *advance (void *p, int incr)
 {
@@ -59,7 +113,21 @@ static inline void *advance (void *p, int incr)
 uint32_t popcount (uint32_t u);
 inline uint32_t lsbindex (uint32_t u);
 
+#ifdef __GNUC__
+#define audio_MIN(a, b) ( __extension__ ({      \
+    __typeof (a) ta = a;                        \
+    __typeof (b) tb = b;                        \
+    ((ta)>(tb)?(tb):(ta));                      \
+}))
+
+#define audio_MAX(a, b) ( __extension__ ({      \
+    __typeof (a) ta = a;                        \
+    __typeof (b) tb = b;                        \
+    ((ta)<(tb)?(tb):(ta));                      \
+}))
+#else
 #define audio_MIN(a, b) ((a)>(b)?(b):(a))
 #define audio_MAX(a, b) ((a)<(b)?(b):(a))
+#endif
 
 #endif  /* audio.h */
index 0be2a61..ca240cc 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * QEMU Audio subsystem header
- * 
- * Copyright (c) 2003-2004 Vassili Karpov (malc)
- * 
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
  * 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
 #ifndef QEMU_AUDIO_INT_H
 #define QEMU_AUDIO_INT_H
 
-#include "vl.h"
+#ifdef CONFIG_COREAUDIO
+#define FLOAT_MIXENG
+/* #define RECIPROCAL */
+#endif
+#include "mixeng.h"
 
-struct pcm_ops;
+struct audio_pcm_ops;
 
-typedef struct HWVoice {
-    int active;
+typedef enum {
+    AUD_OPT_INT,
+    AUD_OPT_FMT,
+    AUD_OPT_STR,
+    AUD_OPT_BOOL
+} audio_option_tag_e;
+
+struct audio_option {
+    const char *name;
+    audio_option_tag_e tag;
+    void *valp;
+    const char *descr;
+    int *overridenp;
+    int overriden;
+};
+
+struct audio_callback {
+    void *opaque;
+    audio_callback_fn_t fn;
+};
+
+struct audio_pcm_info {
+    int bits;
+    int sign;
+    int freq;
+    int nchannels;
+    int align;
+    int shift;
+    int bytes_per_second;
+    int swap_endian;
+};
+
+typedef struct HWVoiceOut {
     int enabled;
     int pending_disable;
     int valid;
-    int freq;
+    struct audio_pcm_info info;
 
     f_sample *clip;
-    audfmt_e fmt;
-    int nchannels;
-
-    int align;
-    int shift;
 
     int rpos;
-    int bufsize;
+    uint64_t ts_helper;
 
-    int bytes_per_second;
     st_sample_t *mix_buf;
 
     int samples;
-    int64_t old_ticks;
-    int nb_voices;
-    struct SWVoice **pvoice;
-    struct pcm_ops *pcm_ops;
-} HWVoice;
+    LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
+    struct audio_pcm_ops *pcm_ops;
+    LIST_ENTRY (HWVoiceOut) entries;
+} HWVoiceOut;
 
-extern struct pcm_ops no_pcm_ops;
-extern struct audio_output_driver no_output_driver;
+typedef struct HWVoiceIn {
+    int enabled;
+    struct audio_pcm_info info;
+
+    t_sample *conv;
 
-extern struct pcm_ops oss_pcm_ops;
-extern struct audio_output_driver oss_output_driver;
+    int wpos;
+    int total_samples_captured;
+    uint64_t ts_helper;
 
-extern struct pcm_ops sdl_pcm_ops;
-extern struct audio_output_driver sdl_output_driver;
+    st_sample_t *conv_buf;
 
-extern struct pcm_ops wav_pcm_ops;
-extern struct audio_output_driver wav_output_driver;
+    int samples;
+    LIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head;
+    struct audio_pcm_ops *pcm_ops;
+    LIST_ENTRY (HWVoiceIn) entries;
+} HWVoiceIn;
 
-extern struct pcm_ops fmod_pcm_ops;
-extern struct audio_output_driver fmod_output_driver;
+struct SWVoiceOut {
+    struct audio_pcm_info info;
+    t_sample *conv;
+    int64_t ratio;
+    st_sample_t *buf;
+    void *rate;
+    int total_hw_samples_mixed;
+    int active;
+    int empty;
+    HWVoiceOut *hw;
+    char *name;
+    volume_t vol;
+    struct audio_callback callback;
+    LIST_ENTRY (SWVoiceOut) entries;
+};
 
-struct audio_output_driver {
+struct SWVoiceIn {
+    int active;
+    struct audio_pcm_info info;
+    int64_t ratio;
+    void *rate;
+    int total_hw_samples_acquired;
+    st_sample_t *buf;
+    f_sample *clip;
+    HWVoiceIn *hw;
+    char *name;
+    volume_t vol;
+    struct audio_callback callback;
+    LIST_ENTRY (SWVoiceIn) entries;
+};
+
+struct audio_driver {
     const char *name;
+    const char *descr;
+    struct audio_option *options;
     void *(*init) (void);
     void (*fini) (void *);
-    struct pcm_ops *pcm_ops;
+    struct audio_pcm_ops *pcm_ops;
     int can_be_default;
-    int max_voices;
-    int voice_size;
+    int max_voices_out;
+    int max_voices_in;
+    int voice_size_out;
+    int voice_size_in;
 };
 
-typedef struct AudioState {
-    int fixed_format;
-    int fixed_freq;
-    int fixed_channels;
-    int fixed_fmt;
-    int nb_hw_voices;
-    int64_t ticks_threshold;
-    int freq_threshold;
-    void *opaque;
-    struct audio_output_driver *drv;
-} AudioState;
-extern AudioState audio_state;
+struct audio_pcm_ops {
+    int  (*init_out)(HWVoiceOut *hw, audsettings_t *as);
+    void (*fini_out)(HWVoiceOut *hw);
+    int  (*run_out) (HWVoiceOut *hw);
+    int  (*write)   (SWVoiceOut *sw, void *buf, int size);
+    int  (*ctl_out) (HWVoiceOut *hw, int cmd, ...);
 
-struct SWVoice {
-    int freq;
-    audfmt_e fmt;
-    int nchannels;
+    int  (*init_in) (HWVoiceIn *hw, audsettings_t *as);
+    void (*fini_in) (HWVoiceIn *hw);
+    int  (*run_in)  (HWVoiceIn *hw);
+    int  (*read)    (SWVoiceIn *sw, void *buf, int size);
+    int  (*ctl_in)  (HWVoiceIn *hw, int cmd, ...);
+};
 
-    int shift;
-    int align;
+struct AudioState {
+    struct audio_driver *drv;
+    void *drv_opaque;
 
-    t_sample *conv;
+    QEMUTimer *ts;
+    LIST_HEAD (card_head, QEMUSoundCard) card_head;
+    LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in;
+    LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out;
+    int nb_hw_voices_out;
+    int nb_hw_voices_in;
+};
 
-    int left;
-    int pos;
-    int bytes_per_second;
-    int64_t ratio;
-    st_sample_t *buf;
-    void *rate;
+extern struct audio_driver no_audio_driver;
+extern struct audio_driver oss_audio_driver;
+extern struct audio_driver sdl_audio_driver;
+extern struct audio_driver wav_audio_driver;
+extern struct audio_driver fmod_audio_driver;
+extern struct audio_driver alsa_audio_driver;
+extern struct audio_driver coreaudio_audio_driver;
+extern struct audio_driver dsound_audio_driver;
+extern volume_t nominal_volume;
 
-    int wpos;
-    int live;
-    int active;
-    int64_t old_ticks;
-    HWVoice *hw;
-    char *name;
-};
+void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as,
+                          int swap_endian);
+void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len);
 
-struct pcm_ops {
-    int  (*init)  (HWVoice *hw, int freq, int nchannels, audfmt_e fmt);
-    void (*fini)  (HWVoice *hw);
-    void (*run)   (HWVoice *hw);
-    int  (*write) (SWVoice *sw, void *buf, int size);
-    int  (*ctl)   (HWVoice *hw, int cmd, ...);
-};
+int  audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len);
+int  audio_pcm_hw_get_live_in (HWVoiceIn *hw);
+
+int  audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int len);
+int  audio_pcm_hw_get_live_out (HWVoiceOut *hw);
+int  audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live);
 
-void      pcm_sw_free_resources (SWVoice *sw);
-int       pcm_sw_alloc_resources (SWVoice *sw);
-void      pcm_sw_fini (SWVoice *sw);
-int       pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
-                       int nchannels, audfmt_e fmt);
-
-void      pcm_hw_clear (HWVoice *hw, void *buf, int len);
-HWVoice * pcm_hw_find_any (HWVoice *hw);
-HWVoice * pcm_hw_find_any_active (HWVoice *hw);
-HWVoice * pcm_hw_find_any_passive (HWVoice *hw);
-HWVoice * pcm_hw_find_specific (HWVoice *hw, int freq,
-                                int nchannels, audfmt_e fmt);
-HWVoice * pcm_hw_add (int freq, int nchannels, audfmt_e fmt);
-int       pcm_hw_add_sw (HWVoice *hw, SWVoice *sw);
-int       pcm_hw_del_sw (HWVoice *hw, SWVoice *sw);
-SWVoice * pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt);
-
-void      pcm_hw_free_resources (HWVoice *hw);
-int       pcm_hw_alloc_resources (HWVoice *hw);
-void      pcm_hw_fini (HWVoice *hw);
-void      pcm_hw_gc (HWVoice *hw);
-int       pcm_hw_get_live (HWVoice *hw);
-int       pcm_hw_get_live2 (HWVoice *hw, int *nb_active);
-void      pcm_hw_dec_live (HWVoice *hw, int decr);
-int       pcm_hw_write (SWVoice *sw, void *buf, int len);
-
-int         audio_get_conf_int (const char *key, int defval);
-const char *audio_get_conf_str (const char *key, const char *defval);
-
-struct audio_output_driver;
+int audio_bug (const char *funcname, int cond);
+void *audio_calloc (const char *funcname, int nmemb, size_t size);
 
 #define VOICE_ENABLE 1
 #define VOICE_DISABLE 2
 
+static inline int audio_ring_dist (int dst, int src, int len)
+{
+    return (dst >= src) ? (dst - src) : (len - src + dst);
+}
+
+static inline int audio_need_to_swap_endian (int endianness)
+{
+#ifdef WORDS_BIGENDIAN
+    return endianness != 1;
+#else
+    return endianness != 0;
+#endif
+}
+
+#if defined __GNUC__
+#define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2)))
+#define INIT_FIELD(f) . f
+#define GCC_FMT_ATTR(n, m) __attribute__ ((__format__ (__printf__, n, m)))
+#else
+#define GCC_ATTR /**/
+#define INIT_FIELD(f) /**/
+#define GCC_FMT_ATTR(n, m)
+#endif
+
+static void GCC_ATTR dolog (const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+}
+
+#ifdef DEBUG
+static void GCC_ATTR ldebug (const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+}
+#else
+#if defined NDEBUG && defined __GNUC__
+#define ldebug(...)
+#elif defined NDEBUG && defined _MSC_VER
+#define ldebug __noop
+#else
+static void GCC_ATTR ldebug (const char *fmt, ...)
+{
+    (void) fmt;
+}
+#endif
+#endif
+
+#undef GCC_ATTR
+
+#define AUDIO_STRINGIFY_(n) #n
+#define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n)
+
+#if defined _MSC_VER || defined __GNUC__
+#define AUDIO_FUNC __FUNCTION__
+#else
+#define AUDIO_FUNC __FILE__ ":" AUDIO_STRINGIFY (__LINE__)
+#endif
+
 #endif /* audio_int.h */
diff --git a/qemu/audio/audio_template.h b/qemu/audio/audio_template.h
new file mode 100644 (file)
index 0000000..23d0242
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+ * QEMU Audio subsystem header
+ *
+ * Copyright (c) 2005 Vassili Karpov (malc)
+ *
+ * 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.
+ */
+
+#ifdef DAC
+#define NAME "playback"
+#define HWBUF hw->mix_buf
+#define TYPE out
+#define HW HWVoiceOut
+#define SW SWVoiceOut
+#else
+#define NAME "capture"
+#define TYPE in
+#define HW HWVoiceIn
+#define SW SWVoiceIn
+#define HWBUF hw->conv_buf
+#endif
+
+static void glue (audio_init_nb_voices_, TYPE) (
+    AudioState *s,
+    struct audio_driver *drv
+    )
+{
+    int max_voices = glue (drv->max_voices_, TYPE);
+    int voice_size = glue (drv->voice_size_, TYPE);
+
+    if (glue (s->nb_hw_voices_, TYPE) > max_voices) {
+        if (!max_voices) {
+#ifdef DAC
+            dolog ("Driver `%s' does not support " NAME "\n", drv->name);
+#endif
+        }
+        else {
+            dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n",
+                   drv->name,
+                   glue (s->nb_hw_voices_, TYPE),
+                   max_voices);
+        }
+        glue (s->nb_hw_voices_, TYPE) = max_voices;
+    }
+
+    if (audio_bug (AUDIO_FUNC, !voice_size && max_voices)) {
+        dolog ("drv=`%s' voice_size=0 max_voices=%d\n",
+               drv->name, max_voices);
+        glue (s->nb_hw_voices_, TYPE) = 0;
+    }
+
+    if (audio_bug (AUDIO_FUNC, voice_size && !max_voices)) {
+        dolog ("drv=`%s' voice_size=%d max_voices=0\n",
+               drv->name, voice_size);
+    }
+}
+
+static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw)
+{
+    if (HWBUF) {
+        qemu_free (HWBUF);
+    }
+
+    HWBUF = NULL;
+}
+
+static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw)
+{
+    HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t));
+    if (!HWBUF) {
+        dolog ("Could not allocate " NAME " buffer (%d samples)\n",
+               hw->samples);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw)
+{
+    if (sw->buf) {
+        qemu_free (sw->buf);
+    }
+
+    if (sw->rate) {
+        st_rate_stop (sw->rate);
+    }
+
+    sw->buf = NULL;
+    sw->rate = NULL;
+}
+
+static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
+{
+    int samples;
+
+#ifdef DAC
+    samples = sw->hw->samples;
+#else
+    samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
+#endif
+
+    sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (st_sample_t));
+    if (!sw->buf) {
+        dolog ("Could not allocate buffer for `%s' (%d samples)\n",
+               SW_NAME (sw), samples);
+        return -1;
+    }
+
+#ifdef DAC
+    sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
+#else
+    sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
+#endif
+    if (!sw->rate) {
+        qemu_free (sw->buf);
+        sw->buf = NULL;
+        return -1;
+    }
+    return 0;
+}
+
+static int glue (audio_pcm_sw_init_, TYPE) (
+    SW *sw,
+    HW *hw,
+    const char *name,
+    audsettings_t *as,
+    int endian
+    )
+{
+    int err;
+
+    audio_pcm_init_info (&sw->info, as, audio_need_to_swap_endian (endian));
+    sw->hw = hw;
+    sw->active = 0;
+#ifdef DAC
+    sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
+    sw->total_hw_samples_mixed = 0;
+    sw->empty = 1;
+#else
+    sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
+#endif
+
+#ifdef DAC
+    sw->conv = mixeng_conv
+#else
+    sw->clip = mixeng_clip
+#endif
+        [sw->info.nchannels == 2]
+        [sw->info.sign]
+        [sw->info.swap_endian]
+        [sw->info.bits == 16];
+
+    sw->name = qemu_strdup (name);
+    err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
+    if (err) {
+        qemu_free (sw->name);
+        sw->name = NULL;
+    }
+    return err;
+}
+
+static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
+{
+    glue (audio_pcm_sw_free_resources_, TYPE) (sw);
+    if (sw->name) {
+        qemu_free (sw->name);
+        sw->name = NULL;
+    }
+}
+
+static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw)
+{
+    LIST_INSERT_HEAD (&hw->sw_head, sw, entries);
+}
+
+static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
+{
+    LIST_REMOVE (sw, entries);
+}
+
+static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp)
+{
+    HW *hw = *hwp;
+
+    if (!hw->sw_head.lh_first) {
+        LIST_REMOVE (hw, entries);
+        glue (s->nb_hw_voices_, TYPE) += 1;
+        glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
+        glue (hw->pcm_ops->fini_, TYPE) (hw);
+        qemu_free (hw);
+        *hwp = NULL;
+    }
+}
+
+static HW *glue (audio_pcm_hw_find_any_, TYPE) (AudioState *s, HW *hw)
+{
+    return hw ? hw->entries.le_next : s->glue (hw_head_, TYPE).lh_first;
+}
+
+static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (AudioState *s, HW *hw)
+{
+    while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) {
+        if (hw->enabled) {
+            return hw;
+        }
+    }
+    return NULL;
+}
+
+static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
+    AudioState *s,
+    HW *hw,
+    audsettings_t *as
+    )
+{
+    while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) {
+        if (audio_pcm_info_eq (&hw->info, as)) {
+            return hw;
+        }
+    }
+    return NULL;
+}
+
+static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
+{
+    HW *hw;
+    struct audio_driver *drv = s->drv;
+
+    if (!glue (s->nb_hw_voices_, TYPE)) {
+        return NULL;
+    }
+
+    if (audio_bug (AUDIO_FUNC, !drv)) {
+        dolog ("No host audio driver\n");
+        return NULL;
+    }
+
+    if (audio_bug (AUDIO_FUNC, !drv->pcm_ops)) {
+        dolog ("Host audio driver without pcm_ops\n");
+        return NULL;
+    }
+
+    hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE));
+    if (!hw) {
+        dolog ("Can not allocate voice `%s' size %d\n",
+               drv->name, glue (drv->voice_size_, TYPE));
+        return NULL;
+    }
+
+    hw->pcm_ops = drv->pcm_ops;
+    LIST_INIT (&hw->sw_head);
+
+    if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
+        goto err0;
+    }
+
+    if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) {
+        dolog ("hw->samples=%d\n", hw->samples);
+        goto err1;
+    }
+
+#ifdef DAC
+    hw->clip = mixeng_clip
+#else
+    hw->conv = mixeng_conv
+#endif
+        [hw->info.nchannels == 2]
+        [hw->info.sign]
+        [hw->info.swap_endian]
+        [hw->info.bits == 16];
+
+    if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
+        goto err1;
+    }
+
+    LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries);
+    glue (s->nb_hw_voices_, TYPE) -= 1;
+    return hw;
+
+ err1:
+    glue (hw->pcm_ops->fini_, TYPE) (hw);
+ err0:
+    qemu_free (hw);
+    return NULL;
+}
+
+static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as)
+{
+    HW *hw;
+
+    if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) {
+        hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as);
+        if (hw) {
+            return hw;
+        }
+    }
+
+    hw = glue (audio_pcm_hw_find_specific_, TYPE) (s, NULL, as);
+    if (hw) {
+        return hw;
+    }
+
+    hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as);
+    if (hw) {
+        return hw;
+    }
+
+    return glue (audio_pcm_hw_find_any_, TYPE) (s, NULL);
+}
+
+static SW *glue (audio_pcm_create_voice_pair_, TYPE) (
+    AudioState *s,
+    const char *sw_name,
+    audsettings_t *as,
+    int sw_endian
+    )
+{
+    SW *sw;
+    HW *hw;
+    audsettings_t hw_as;
+
+    if (glue (conf.fixed_, TYPE).enabled) {
+        hw_as = glue (conf.fixed_, TYPE).settings;
+    }
+    else {
+        hw_as = *as;
+    }
+
+    sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw));
+    if (!sw) {
+        dolog ("Could not allocate soft voice `%s' (%zu bytes)\n",
+               sw_name ? sw_name : "unknown", sizeof (*sw));
+        goto err1;
+    }
+
+    hw = glue (audio_pcm_hw_add_, TYPE) (s, &hw_as);
+    if (!hw) {
+        goto err2;
+    }
+
+    glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw);
+
+    if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as, sw_endian)) {
+        goto err3;
+    }
+
+    return sw;
+
+err3:
+    glue (audio_pcm_hw_del_sw_, TYPE) (sw);
+    glue (audio_pcm_hw_gc_, TYPE) (s, &hw);
+err2:
+    qemu_free (sw);
+err1:
+    return NULL;
+}
+
+static void glue (audio_close_, TYPE) (AudioState *s, SW *sw)
+{
+    glue (audio_pcm_sw_fini_, TYPE) (sw);
+    glue (audio_pcm_hw_del_sw_, TYPE) (sw);
+    glue (audio_pcm_hw_gc_, TYPE) (s, &sw->hw);
+    qemu_free (sw);
+}
+
+void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw)
+{
+    if (sw) {
+        if (audio_bug (AUDIO_FUNC, !card || !card->audio)) {
+            dolog ("card=%p card->audio=%p\n",
+                   card, card ? card->audio : NULL);
+            return;
+        }
+
+        glue (audio_close_, TYPE) (card->audio, sw);
+    }
+}
+
+SW *glue (AUD_open_, TYPE) (
+    QEMUSoundCard *card,
+    SW *sw,
+    const char *name,
+    void *callback_opaque ,
+    audio_callback_fn_t callback_fn,
+    audsettings_t *as,
+    int sw_endian
+    )
+{
+    AudioState *s;
+#ifdef DAC
+    int live = 0;
+    SW *old_sw = NULL;
+#endif
+
+    ldebug ("open %s, freq %d, nchannels %d, fmt %d\n",
+            name, as->freq, as->nchannels, as->fmt);
+
+    if (audio_bug (AUDIO_FUNC,
+                   !card || !card->audio || !name || !callback_fn || !as)) {
+        dolog ("card=%p card->audio=%p name=%p callback_fn=%p as=%p\n",
+               card, card ? card->audio : NULL, name, callback_fn, as);
+        goto fail;
+    }
+
+    s = card->audio;
+
+    if (audio_bug (AUDIO_FUNC, audio_validate_settigs (as))) {
+        audio_print_settings (as);
+        goto fail;
+    }
+
+    if (audio_bug (AUDIO_FUNC, !s->drv)) {
+        dolog ("Can not open `%s' (no host audio driver)\n", name);
+        goto fail;
+    }
+
+    if (sw && audio_pcm_info_eq (&sw->info, as)) {
+        return sw;
+    }
+
+#ifdef DAC
+    if (conf.plive && sw && (!sw->active && !sw->empty)) {
+        live = sw->total_hw_samples_mixed;
+
+#ifdef DEBUG_PLIVE
+        dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live);
+        dolog ("Old %s freq %d, bits %d, channels %d\n",
+               SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels);
+        dolog ("New %s freq %d, bits %d, channels %d\n",
+               name,
+               freq,
+               (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8,
+               nchannels);
+#endif
+
+        if (live) {
+            old_sw = sw;
+            old_sw->callback.fn = NULL;
+            sw = NULL;
+        }
+    }
+#endif
+
+    if (!glue (conf.fixed_, TYPE).enabled && sw) {
+        glue (AUD_close_, TYPE) (card, sw);
+        sw = NULL;
+    }
+
+    if (sw) {
+        HW *hw = sw->hw;
+
+        if (!hw) {
+            dolog ("Internal logic error voice `%s' has no hardware store\n",
+                   SW_NAME (sw));
+            goto fail;
+        }
+
+        glue (audio_pcm_sw_fini_, TYPE) (sw);
+        if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as, sw_endian)) {
+            goto fail;
+        }
+    }
+    else {
+        sw = glue (audio_pcm_create_voice_pair_, TYPE) (s, name, as, sw_endian);
+        if (!sw) {
+            dolog ("Failed to create voice `%s'\n", name);
+            return NULL;
+        }
+    }
+
+    if (sw) {
+        sw->vol = nominal_volume;
+        sw->callback.fn = callback_fn;
+        sw->callback.opaque = callback_opaque;
+
+#ifdef DAC
+        if (live) {
+            int mixed =
+                (live << old_sw->info.shift)
+                * old_sw->info.bytes_per_second
+                / sw->info.bytes_per_second;
+
+#ifdef DEBUG_PLIVE
+            dolog ("Silence will be mixed %d\n", mixed);
+#endif
+            sw->total_hw_samples_mixed += mixed;
+        }
+#endif
+
+#ifdef DEBUG_AUDIO
+        dolog ("%s\n", name);
+        audio_pcm_print_info ("hw", &sw->hw->info);
+        audio_pcm_print_info ("sw", &sw->info);
+#endif
+    }
+
+    return sw;
+
+ fail:
+    glue (AUD_close_, TYPE) (card, sw);
+    return NULL;
+}
+
+int glue (AUD_is_active_, TYPE) (SW *sw)
+{
+    return sw ? sw->active : 0;
+}
+
+void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
+{
+    if (!sw) {
+        return;
+    }
+
+    ts->old_ts = sw->hw->ts_helper;
+}
+
+uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
+{
+    uint64_t delta, cur_ts, old_ts;
+
+    if (!sw) {
+        return 0;
+    }
+
+    cur_ts = sw->hw->ts_helper;
+    old_ts = ts->old_ts;
+    /* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */
+
+    if (cur_ts >= old_ts) {
+        delta = cur_ts - old_ts;
+    }
+    else {
+        delta = UINT64_MAX - old_ts + cur_ts;
+    }
+
+    if (!delta) {
+        return 0;
+    }
+
+    return (delta * sw->hw->info.freq) / 1000000;
+}
+
+#undef TYPE
+#undef HW
+#undef SW
+#undef HWBUF
+#undef NAME
diff --git a/qemu/audio/coreaudio.c b/qemu/audio/coreaudio.c
new file mode 100644 (file)
index 0000000..534fb3e
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ * QEMU OS X CoreAudio audio driver
+ *
+ * Copyright (c) 2005 Mike Kronenberg
+ *
+ * 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 <CoreAudio/CoreAudio.h>
+#include <string.h>             /* strerror */
+#include <pthread.h>            /* pthread_X */
+
+#include "vl.h"
+
+#define AUDIO_CAP "coreaudio"
+#include "audio_int.h"
+
+struct {
+    int buffer_frames;
+    int nbuffers;
+    int isAtexit;
+} conf = {
+    .buffer_frames = 512,
+    .nbuffers = 4,
+    .isAtexit = 0
+};
+
+typedef struct coreaudioVoiceOut {
+    HWVoiceOut hw;
+    pthread_mutex_t mutex;
+    int isAtexit;
+    AudioDeviceID outputDeviceID;
+    UInt32 audioDevicePropertyBufferFrameSize;
+    AudioStreamBasicDescription outputStreamBasicDescription;
+    int live;
+    int decr;
+    int rpos;
+} coreaudioVoiceOut;
+
+static void coreaudio_logstatus (OSStatus status)
+{
+    char *str = "BUG";
+
+    switch(status) {
+    case kAudioHardwareNoError:
+        str = "kAudioHardwareNoError";
+        break;
+
+    case kAudioHardwareNotRunningError:
+        str = "kAudioHardwareNotRunningError";
+        break;
+
+    case kAudioHardwareUnspecifiedError:
+        str = "kAudioHardwareUnspecifiedError";
+        break;
+
+    case kAudioHardwareUnknownPropertyError:
+        str = "kAudioHardwareUnknownPropertyError";
+        break;
+
+    case kAudioHardwareBadPropertySizeError:
+        str = "kAudioHardwareBadPropertySizeError";
+        break;
+
+    case kAudioHardwareIllegalOperationError:
+        str = "kAudioHardwareIllegalOperationError";
+        break;
+
+    case kAudioHardwareBadDeviceError:
+        str = "kAudioHardwareBadDeviceError";
+        break;
+
+    case kAudioHardwareBadStreamError:
+        str = "kAudioHardwareBadStreamError";
+        break;
+
+    case kAudioHardwareUnsupportedOperationError:
+        str = "kAudioHardwareUnsupportedOperationError";
+        break;
+
+    case kAudioDeviceUnsupportedFormatError:
+        str = "kAudioDeviceUnsupportedFormatError";
+        break;
+
+    case kAudioDevicePermissionsError:
+        str = "kAudioDevicePermissionsError";
+        break;
+
+    default:
+        AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
+        return;
+    }
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", str);
+}
+
+static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
+    OSStatus status,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_log (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    coreaudio_logstatus (status);
+}
+
+static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
+    OSStatus status,
+    const char *typ,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    coreaudio_logstatus (status);
+}
+
+static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
+{
+    OSStatus status;
+    UInt32 result = 0;
+    UInt32 propertySize = sizeof(outputDeviceID);
+    status = AudioDeviceGetProperty(
+        outputDeviceID, 0, 0,
+        kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr(status,
+                         "Could not determine whether Device is playing\n");
+    }
+    return result;
+}
+
+static void coreaudio_atexit (void)
+{
+    conf.isAtexit = 1;
+}
+
+static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
+{
+    int err;
+
+    err = pthread_mutex_lock (&core->mutex);
+    if (err) {
+        dolog ("Could not lock voice for %s\nReason: %s\n",
+               fn_name, strerror (err));
+        return -1;
+    }
+    return 0;
+}
+
+static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
+{
+    int err;
+
+    err = pthread_mutex_unlock (&core->mutex);
+    if (err) {
+        dolog ("Could not unlock voice for %s\nReason: %s\n",
+               fn_name, strerror (err));
+        return -1;
+    }
+    return 0;
+}
+
+static int coreaudio_run_out (HWVoiceOut *hw)
+{
+    int live, decr;
+    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
+
+    if (coreaudio_lock (core, "coreaudio_run_out")) {
+        return 0;
+    }
+
+    live = audio_pcm_hw_get_live_out (hw);
+
+    if (core->decr > live) {
+        ldebug ("core->decr %d live %d core->live %d\n",
+                core->decr,
+                live,
+                core->live);
+    }
+
+    decr = audio_MIN (core->decr, live);
+    core->decr -= decr;
+
+    core->live = live - decr;
+    hw->rpos = core->rpos;
+
+    coreaudio_unlock (core, "coreaudio_run_out");
+    return decr;
+}
+
+/* callback to feed audiooutput buffer */
+static OSStatus audioDeviceIOProc(
+    AudioDeviceID inDevice,
+    const AudioTimeStamp* inNow,
+    const AudioBufferList* inInputData,
+    const AudioTimeStamp* inInputTime,
+    AudioBufferList* outOutputData,
+    const AudioTimeStamp* inOutputTime,
+    void* hwptr)
+{
+    UInt32 frame, frameCount;
+    float *out = outOutputData->mBuffers[0].mData;
+    HWVoiceOut *hw = hwptr;
+    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
+    int rpos, live;
+    st_sample_t *src;
+#ifndef FLOAT_MIXENG
+#ifdef RECIPROCAL
+    const float scale = 1.f / UINT_MAX;
+#else
+    const float scale = UINT_MAX;
+#endif
+#endif
+
+    if (coreaudio_lock (core, "audioDeviceIOProc")) {
+        inInputTime = 0;
+        return 0;
+    }
+
+    frameCount = core->audioDevicePropertyBufferFrameSize;
+    live = core->live;
+
+    /* if there are not enough samples, set signal and return */
+    if (live < frameCount) {
+        inInputTime = 0;
+        coreaudio_unlock (core, "audioDeviceIOProc(empty)");
+        return 0;
+    }
+
+    rpos = core->rpos;
+    src = hw->mix_buf + rpos;
+
+    /* fill buffer */
+    for (frame = 0; frame < frameCount; frame++) {
+#ifdef FLOAT_MIXENG
+        *out++ = src[frame].l; /* left channel */
+        *out++ = src[frame].r; /* right channel */
+#else
+#ifdef RECIPROCAL
+        *out++ = src[frame].l * scale; /* left channel */
+        *out++ = src[frame].r * scale; /* right channel */
+#else
+        *out++ = src[frame].l / scale; /* left channel */
+        *out++ = src[frame].r / scale; /* right channel */
+#endif
+#endif
+    }
+
+    /* cleanup */
+    mixeng_clear (src, frameCount);
+    rpos = (rpos + frameCount) % hw->samples;
+    core->decr += frameCount;
+    core->rpos = rpos;
+
+    coreaudio_unlock (core, "audioDeviceIOProc");
+    return 0;
+}
+
+static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
+{
+    OSStatus status;
+    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
+    UInt32 propertySize;
+    int err;
+    int bits = 8;
+    int endianess = 0;
+    const char *typ = "playback";
+    AudioValueRange frameRange;
+
+    /* create mutex */
+    err = pthread_mutex_init(&core->mutex, NULL);
+    if (err) {
+        dolog("Could not create mutex\nReason: %s\n", strerror (err));
+        return -1;
+    }
+
+    if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) {
+        bits = 16;
+        endianess = 1;
+    }
+
+    audio_pcm_init_info (
+        &hw->info,
+        as,
+        /* Following is irrelevant actually since we do not use
+           mixengs clipping routines */
+        audio_need_to_swap_endian (endianess)
+        );
+
+    /* open default output device */
+    propertySize = sizeof(core->outputDeviceID);
+    status = AudioHardwareGetProperty(
+        kAudioHardwarePropertyDefaultOutputDevice,
+        &propertySize,
+        &core->outputDeviceID);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ,
+                           "Could not get default output Device\n");
+        return -1;
+    }
+    if (core->outputDeviceID == kAudioDeviceUnknown) {
+        dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
+        return -1;
+    }
+
+    /* get minimum and maximum buffer frame sizes */
+    propertySize = sizeof(frameRange);
+    status = AudioDeviceGetProperty(
+        core->outputDeviceID,
+        0,
+        0,
+        kAudioDevicePropertyBufferFrameSizeRange,
+        &propertySize,
+        &frameRange);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ,
+                           "Could not get device buffer frame range\n");
+        return -1;
+    }
+
+    if (frameRange.mMinimum > conf.buffer_frames) {
+        core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
+        dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
+    }
+    else if (frameRange.mMaximum < conf.buffer_frames) {
+        core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
+        dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
+    }
+    else {
+        core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
+    }
+
+    /* set Buffer Frame Size */
+    propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
+    status = AudioDeviceSetProperty(
+        core->outputDeviceID,
+        NULL,
+        0,
+        false,
+        kAudioDevicePropertyBufferFrameSize,
+        propertySize,
+        &core->audioDevicePropertyBufferFrameSize);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ,
+                           "Could not set device buffer frame size %ld\n",
+                           core->audioDevicePropertyBufferFrameSize);
+        return -1;
+    }
+
+    /* get Buffer Frame Size */
+    propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
+    status = AudioDeviceGetProperty(
+        core->outputDeviceID,
+        0,
+        false,
+        kAudioDevicePropertyBufferFrameSize,
+        &propertySize,
+        &core->audioDevicePropertyBufferFrameSize);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ,
+                           "Could not get device buffer frame size\n");
+        return -1;
+    }
+    hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
+
+    /* get StreamFormat */
+    propertySize = sizeof(core->outputStreamBasicDescription);
+    status = AudioDeviceGetProperty(
+        core->outputDeviceID,
+        0,
+        false,
+        kAudioDevicePropertyStreamFormat,
+        &propertySize,
+        &core->outputStreamBasicDescription);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ,
+                           "Could not get Device Stream properties\n");
+        core->outputDeviceID = kAudioDeviceUnknown;
+        return -1;
+    }
+
+    /* set Samplerate */
+    core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
+    propertySize = sizeof(core->outputStreamBasicDescription);
+    status = AudioDeviceSetProperty(
+        core->outputDeviceID,
+        0,
+        0,
+        0,
+        kAudioDevicePropertyStreamFormat,
+        propertySize,
+        &core->outputStreamBasicDescription);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
+                           as->freq);
+        core->outputDeviceID = kAudioDeviceUnknown;
+        return -1;
+    }
+
+    /* set Callback */
+    status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
+    if (status != kAudioHardwareNoError) {
+        coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
+        core->outputDeviceID = kAudioDeviceUnknown;
+        return -1;
+    }
+
+    /* start Playback */
+    if (!isPlaying(core->outputDeviceID)) {
+        status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
+        if (status != kAudioHardwareNoError) {
+            coreaudio_logerr2 (status, typ, "Could not start playback\n");
+            AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
+            core->outputDeviceID = kAudioDeviceUnknown;
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static void coreaudio_fini_out (HWVoiceOut *hw)
+{
+    OSStatus status;
+    int err;
+    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
+
+    if (!conf.isAtexit) {
+        /* stop playback */
+        if (isPlaying(core->outputDeviceID)) {
+            status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
+            if (status != kAudioHardwareNoError) {
+                coreaudio_logerr (status, "Could not stop playback\n");
+            }
+        }
+
+        /* remove callback */
+        status = AudioDeviceRemoveIOProc(core->outputDeviceID,
+                                         audioDeviceIOProc);
+        if (status != kAudioHardwareNoError) {
+            coreaudio_logerr (status, "Could not remove IOProc\n");
+        }
+    }
+    core->outputDeviceID = kAudioDeviceUnknown;
+
+    /* destroy mutex */
+    err = pthread_mutex_destroy(&core->mutex);
+    if (err) {
+        dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
+    }
+}
+
+static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    OSStatus status;
+    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        /* start playback */
+        if (!isPlaying(core->outputDeviceID)) {
+            status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
+            if (status != kAudioHardwareNoError) {
+                coreaudio_logerr (status, "Could not resume playback\n");
+            }
+        }
+        break;
+
+    case VOICE_DISABLE:
+        /* stop playback */
+        if (!conf.isAtexit) {
+            if (isPlaying(core->outputDeviceID)) {
+                status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
+                if (status != kAudioHardwareNoError) {
+                    coreaudio_logerr (status, "Could not pause playback\n");
+                }
+            }
+        }
+        break;
+    }
+    return 0;
+}
+
+static void *coreaudio_audio_init (void)
+{
+    atexit(coreaudio_atexit);
+    return &coreaudio_audio_init;
+}
+
+static void coreaudio_audio_fini (void *opaque)
+{
+    (void) opaque;
+}
+
+static struct audio_option coreaudio_options[] = {
+    {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames,
+     "Size of the buffer in frames", NULL, 0},
+    {"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers,
+     "Number of buffers", NULL, 0},
+    {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+static struct audio_pcm_ops coreaudio_pcm_ops = {
+    coreaudio_init_out,
+    coreaudio_fini_out,
+    coreaudio_run_out,
+    coreaudio_write,
+    coreaudio_ctl_out,
+
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL
+};
+
+struct audio_driver coreaudio_audio_driver = {
+    INIT_FIELD (name           = ) "coreaudio",
+    INIT_FIELD (descr          = )
+    "CoreAudio http://developer.apple.com/audio/coreaudio.html",
+    INIT_FIELD (options        = ) coreaudio_options,
+    INIT_FIELD (init           = ) coreaudio_audio_init,
+    INIT_FIELD (fini           = ) coreaudio_audio_fini,
+    INIT_FIELD (pcm_ops        = ) &coreaudio_pcm_ops,
+    INIT_FIELD (can_be_default = ) 1,
+    INIT_FIELD (max_voices_out = ) 1,
+    INIT_FIELD (max_voices_in  = ) 0,
+    INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
+    INIT_FIELD (voice_size_in  = ) 0
+};
diff --git a/qemu/audio/dsound_template.h b/qemu/audio/dsound_template.h
new file mode 100644 (file)
index 0000000..38ba5b9
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * QEMU DirectSound audio driver header
+ *
+ * Copyright (c) 2005 Vassili Karpov (malc)
+ *
+ * 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.
+ */
+#ifdef DSBTYPE_IN
+#define NAME "capture buffer"
+#define TYPE in
+#define IFACE IDirectSoundCaptureBuffer
+#define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER
+#define FIELD dsound_capture_buffer
+#else
+#define NAME "playback buffer"
+#define TYPE out
+#define IFACE IDirectSoundBuffer
+#define BUFPTR LPDIRECTSOUNDBUFFER
+#define FIELD dsound_buffer
+#endif
+
+static int glue (dsound_unlock_, TYPE) (
+    BUFPTR buf,
+    LPVOID p1,
+    LPVOID p2,
+    DWORD blen1,
+    DWORD blen2
+    )
+{
+    HRESULT hr;
+
+    hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2);
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not unlock " NAME "\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int glue (dsound_lock_, TYPE) (
+    BUFPTR buf,
+    struct audio_pcm_info *info,
+    DWORD pos,
+    DWORD len,
+    LPVOID *p1p,
+    LPVOID *p2p,
+    DWORD *blen1p,
+    DWORD *blen2p,
+    int entire
+    )
+{
+    HRESULT hr;
+    int i;
+    LPVOID p1 = NULL, p2 = NULL;
+    DWORD blen1 = 0, blen2 = 0;
+
+    for (i = 0; i < conf.lock_retries; ++i) {
+        hr = glue (IFACE, _Lock) (
+            buf,
+            pos,
+            len,
+            &p1,
+            &blen1,
+            &p2,
+            &blen2,
+            (entire
+#ifdef DSBTYPE_IN
+             ? DSCBLOCK_ENTIREBUFFER
+#else
+             ? DSBLOCK_ENTIREBUFFER
+#endif
+             : 0)
+            );
+
+        if (FAILED (hr)) {
+#ifndef DSBTYPE_IN
+            if (hr == DSERR_BUFFERLOST) {
+                if (glue (dsound_restore_, TYPE) (buf)) {
+                    dsound_logerr (hr, "Could not lock " NAME "\n");
+                    goto fail;
+                }
+                continue;
+            }
+#endif
+            dsound_logerr (hr, "Could not lock " NAME "\n");
+            goto fail;
+        }
+
+        break;
+    }
+
+    if (i == conf.lock_retries) {
+        dolog ("%d attempts to lock " NAME " failed\n", i);
+        goto fail;
+    }
+
+    if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) {
+        dolog ("DirectSound returned misaligned buffer %ld %ld\n",
+               blen1, blen2);
+        glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2);
+        goto fail;
+    }
+
+    if (!p1 && blen1) {
+        dolog ("warning: !p1 && blen1=%ld\n", blen1);
+        blen1 = 0;
+    }
+
+    if (!p2 && blen2) {
+        dolog ("warning: !p2 && blen2=%ld\n", blen2);
+        blen2 = 0;
+    }
+
+    *p1p = p1;
+    *p2p = p2;
+    *blen1p = blen1;
+    *blen2p = blen2;
+    return 0;
+
+ fail:
+    *p1p = NULL - 1;
+    *p2p = NULL - 1;
+    *blen1p = -1;
+    *blen2p = -1;
+    return -1;
+}
+
+#ifdef DSBTYPE_IN
+static void dsound_fini_in (HWVoiceIn *hw)
+#else
+static void dsound_fini_out (HWVoiceOut *hw)
+#endif
+{
+    HRESULT hr;
+#ifdef DSBTYPE_IN
+    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
+#else
+    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
+#endif
+
+    if (ds->FIELD) {
+        hr = glue (IFACE, _Stop) (ds->FIELD);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not stop " NAME "\n");
+        }
+
+        hr = glue (IFACE, _Release) (ds->FIELD);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not release " NAME "\n");
+        }
+        ds->FIELD = NULL;
+    }
+}
+
+#ifdef DSBTYPE_IN
+static int dsound_init_in (HWVoiceIn *hw, audsettings_t *as)
+#else
+static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as)
+#endif
+{
+    int err;
+    HRESULT hr;
+    dsound *s = &glob_dsound;
+    WAVEFORMATEX wfx;
+    audsettings_t obt_as;
+#ifdef DSBTYPE_IN
+    const char *typ = "ADC";
+    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
+    DSCBUFFERDESC bd;
+    DSCBCAPS bc;
+#else
+    const char *typ = "DAC";
+    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
+    DSBUFFERDESC bd;
+    DSBCAPS bc;
+#endif
+
+    err = waveformat_from_audio_settings (&wfx, as);
+    if (err) {
+        return -1;
+    }
+
+    memset (&bd, 0, sizeof (bd));
+    bd.dwSize = sizeof (bd);
+    bd.lpwfxFormat = &wfx;
+#ifdef DSBTYPE_IN
+    bd.dwBufferBytes = conf.bufsize_in;
+    hr = IDirectSoundCapture_CreateCaptureBuffer (
+        s->dsound_capture,
+        &bd,
+        &ds->dsound_capture_buffer,
+        NULL
+        );
+#else
+    bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
+    bd.dwBufferBytes = conf.bufsize_out;
+    hr = IDirectSound_CreateSoundBuffer (
+        s->dsound,
+        &bd,
+        &ds->dsound_buffer,
+        NULL
+        );
+#endif
+
+    if (FAILED (hr)) {
+        dsound_logerr2 (hr, typ, "Could not create " NAME "\n");
+        return -1;
+    }
+
+    hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL);
+    if (FAILED (hr)) {
+        dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
+        goto fail0;
+    }
+
+#ifdef DEBUG_DSOUND
+    dolog (NAME "\n");
+    print_wave_format (&wfx);
+#endif
+
+    memset (&bc, 0, sizeof (bc));
+    bc.dwSize = sizeof (bc);
+
+    hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc);
+    if (FAILED (hr)) {
+        dsound_logerr2 (hr, typ, "Could not get " NAME " format\n");
+        goto fail0;
+    }
+
+    err = waveformat_to_audio_settings (&wfx, &obt_as);
+    if (err) {
+        goto fail0;
+    }
+
+    ds->first_time = 1;
+
+    audio_pcm_init_info (&hw->info, &obt_as, audio_need_to_swap_endian (0));
+
+    if (bc.dwBufferBytes & hw->info.align) {
+        dolog (
+            "GetCaps returned misaligned buffer size %ld, alignment %d\n",
+            bc.dwBufferBytes, hw->info.align + 1
+            );
+    }
+    hw->samples = bc.dwBufferBytes >> hw->info.shift;
+
+#ifdef DEBUG_DSOUND
+    dolog ("caps %ld, desc %ld\n",
+           bc.dwBufferBytes, bd.dwBufferBytes);
+
+    dolog ("bufsize %d, freq %d, chan %d, fmt %d\n",
+           hw->bufsize, settings.freq, settings.nchannels, settings.fmt);
+#endif
+    return 0;
+
+ fail0:
+    glue (dsound_fini_, TYPE) (hw);
+    return -1;
+}
+
+#undef NAME
+#undef TYPE
+#undef IFACE
+#undef BUFPTR
+#undef FIELD
diff --git a/qemu/audio/dsoundaudio.c b/qemu/audio/dsoundaudio.c
new file mode 100644 (file)
index 0000000..63c5a50
--- /dev/null
@@ -0,0 +1,1076 @@
+/*
+ * QEMU DirectSound audio driver
+ *
+ * Copyright (c) 2005 Vassili Karpov (malc)
+ *
+ * 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.
+ */
+
+/*
+ * SEAL 1.07 by Carlos 'pel' Hasan was used as documentation
+ */
+
+#include "vl.h"
+
+#define AUDIO_CAP "dsound"
+#include "audio_int.h"
+
+#include <windows.h>
+#include <objbase.h>
+#include <dsound.h>
+
+/* #define DEBUG_DSOUND */
+
+static struct {
+    int lock_retries;
+    int restore_retries;
+    int getstatus_retries;
+    int set_primary;
+    int bufsize_in;
+    int bufsize_out;
+    audsettings_t settings;
+    int latency_millis;
+} conf = {
+    1,
+    1,
+    1,
+    0,
+    16384,
+    16384,
+    {
+        44100,
+        2,
+        AUD_FMT_S16
+    },
+    10
+};
+
+typedef struct {
+    LPDIRECTSOUND dsound;
+    LPDIRECTSOUNDCAPTURE dsound_capture;
+    LPDIRECTSOUNDBUFFER dsound_primary_buffer;
+    audsettings_t settings;
+} dsound;
+
+static dsound glob_dsound;
+
+typedef struct {
+    HWVoiceOut hw;
+    LPDIRECTSOUNDBUFFER dsound_buffer;
+    DWORD old_pos;
+    int first_time;
+#ifdef DEBUG_DSOUND
+    DWORD old_ppos;
+    DWORD played;
+    DWORD mixed;
+#endif
+} DSoundVoiceOut;
+
+typedef struct {
+    HWVoiceIn hw;
+    int first_time;
+    LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
+} DSoundVoiceIn;
+
+static void dsound_log_hresult (HRESULT hr)
+{
+    const char *str = "BUG";
+
+    switch (hr) {
+    case DS_OK:
+        str = "The method succeeded";
+        break;
+#ifdef DS_NO_VIRTUALIZATION
+    case DS_NO_VIRTUALIZATION:
+        str = "The buffer was created, but another 3D algorithm was substituted";
+        break;
+#endif
+#ifdef DS_INCOMPLETE
+    case DS_INCOMPLETE:
+        str = "The method succeeded, but not all the optional effects were obtained";
+        break;
+#endif
+#ifdef DSERR_ACCESSDENIED
+    case DSERR_ACCESSDENIED:
+        str = "The request failed because access was denied";
+        break;
+#endif
+#ifdef DSERR_ALLOCATED
+    case DSERR_ALLOCATED:
+        str = "The request failed because resources, such as a priority level, were already in use by another caller";
+        break;
+#endif
+#ifdef DSERR_ALREADYINITIALIZED
+    case DSERR_ALREADYINITIALIZED:
+        str = "The object is already initialized";
+        break;
+#endif
+#ifdef DSERR_BADFORMAT
+    case DSERR_BADFORMAT:
+        str = "The specified wave format is not supported";
+        break;
+#endif
+#ifdef DSERR_BADSENDBUFFERGUID
+    case DSERR_BADSENDBUFFERGUID:
+        str = "The GUID specified in an audiopath file does not match a valid mix-in buffer";
+        break;
+#endif
+#ifdef DSERR_BUFFERLOST
+    case DSERR_BUFFERLOST:
+        str = "The buffer memory has been lost and must be restored";
+        break;
+#endif
+#ifdef DSERR_BUFFERTOOSMALL
+    case DSERR_BUFFERTOOSMALL:
+        str = "The buffer size is not great enough to enable effects processing";
+        break;
+#endif
+#ifdef DSERR_CONTROLUNAVAIL
+    case DSERR_CONTROLUNAVAIL:
+        str = "The buffer control (volume, pan, and so on) requested by the caller is not available. Controls must be specified when the buffer is created, using the dwFlags member of DSBUFFERDESC";
+        break;
+#endif
+#ifdef DSERR_DS8_REQUIRED
+    case DSERR_DS8_REQUIRED:
+        str = "A DirectSound object of class CLSID_DirectSound8 or later is required for the requested functionality. For more information, see IDirectSound8 Interface";
+        break;
+#endif
+#ifdef DSERR_FXUNAVAILABLE
+    case DSERR_FXUNAVAILABLE:
+        str = "The effects requested could not be found on the system, or they are in the wrong order or in the wrong location; for example, an effect expected in hardware was found in software";
+        break;
+#endif
+#ifdef DSERR_GENERIC
+    case DSERR_GENERIC :
+        str = "An undetermined error occurred inside the DirectSound subsystem";
+        break;
+#endif
+#ifdef DSERR_INVALIDCALL
+    case DSERR_INVALIDCALL:
+        str = "This function is not valid for the current state of this object";
+        break;
+#endif
+#ifdef DSERR_INVALIDPARAM
+    case DSERR_INVALIDPARAM:
+        str = "An invalid parameter was passed to the returning function";
+        break;
+#endif
+#ifdef DSERR_NOAGGREGATION
+    case DSERR_NOAGGREGATION:
+        str = "The object does not support aggregation";
+        break;
+#endif
+#ifdef DSERR_NODRIVER
+    case DSERR_NODRIVER:
+        str = "No sound driver is available for use, or the given GUID is not a valid DirectSound device ID";
+        break;
+#endif
+#ifdef DSERR_NOINTERFACE
+    case DSERR_NOINTERFACE:
+        str = "The requested COM interface is not available";
+        break;
+#endif
+#ifdef DSERR_OBJECTNOTFOUND
+    case DSERR_OBJECTNOTFOUND:
+        str = "The requested object was not found";
+        break;
+#endif
+#ifdef DSERR_OTHERAPPHASPRIO
+    case DSERR_OTHERAPPHASPRIO:
+        str = "Another application has a higher priority level, preventing this call from succeeding";
+        break;
+#endif
+#ifdef DSERR_OUTOFMEMORY
+    case DSERR_OUTOFMEMORY:
+        str = "The DirectSound subsystem could not allocate sufficient memory to complete the caller's request";
+        break;
+#endif
+#ifdef DSERR_PRIOLEVELNEEDED
+    case DSERR_PRIOLEVELNEEDED:
+        str = "A cooperative level of DSSCL_PRIORITY or higher is required";
+        break;
+#endif
+#ifdef DSERR_SENDLOOP
+    case DSERR_SENDLOOP:
+        str = "A circular loop of send effects was detected";
+        break;
+#endif
+#ifdef DSERR_UNINITIALIZED
+    case DSERR_UNINITIALIZED:
+        str = "The Initialize method has not been called or has not been called successfully before other methods were called";
+        break;
+#endif
+#ifdef DSERR_UNSUPPORTED
+    case DSERR_UNSUPPORTED:
+        str = "The function called is not supported at this time";
+        break;
+#endif
+    default:
+        AUD_log (AUDIO_CAP, "Reason: Unknown (HRESULT %#lx)\n", hr);
+        return;
+    }
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", str);
+}
+
+static void GCC_FMT_ATTR (2, 3) dsound_logerr (
+    HRESULT hr,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    dsound_log_hresult (hr);
+}
+
+static void GCC_FMT_ATTR (3, 4) dsound_logerr2 (
+    HRESULT hr,
+    const char *typ,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    dsound_log_hresult (hr);
+}
+
+static DWORD millis_to_bytes (struct audio_pcm_info *info, DWORD millis)
+{
+    return (millis * info->bytes_per_second) / 1000;
+}
+
+#ifdef DEBUG_DSOUND
+static void print_wave_format (WAVEFORMATEX *wfx)
+{
+    dolog ("tag             = %d\n", wfx->wFormatTag);
+    dolog ("nChannels       = %d\n", wfx->nChannels);
+    dolog ("nSamplesPerSec  = %ld\n", wfx->nSamplesPerSec);
+    dolog ("nAvgBytesPerSec = %ld\n", wfx->nAvgBytesPerSec);
+    dolog ("nBlockAlign     = %d\n", wfx->nBlockAlign);
+    dolog ("wBitsPerSample  = %d\n", wfx->wBitsPerSample);
+    dolog ("cbSize          = %d\n", wfx->cbSize);
+}
+#endif
+
+static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb)
+{
+    HRESULT hr;
+    int i;
+
+    for (i = 0; i < conf.restore_retries; ++i) {
+        hr = IDirectSoundBuffer_Restore (dsb);
+
+        switch (hr) {
+        case DS_OK:
+            return 0;
+
+        case DSERR_BUFFERLOST:
+            continue;
+
+        default:
+            dsound_logerr (hr, "Could not restore playback buffer\n");
+            return -1;
+        }
+    }
+
+    dolog ("%d attempts to restore playback buffer failed\n", i);
+    return -1;
+}
+
+static int waveformat_from_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as)
+{
+    memset (wfx, 0, sizeof (*wfx));
+
+    wfx->wFormatTag = WAVE_FORMAT_PCM;
+    wfx->nChannels = as->nchannels;
+    wfx->nSamplesPerSec = as->freq;
+    wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2);
+    wfx->nBlockAlign = 1 << (as->nchannels == 2);
+    wfx->cbSize = 0;
+
+    switch (as->fmt) {
+    case AUD_FMT_S8:
+        wfx->wBitsPerSample = 8;
+        break;
+
+    case AUD_FMT_U8:
+        wfx->wBitsPerSample = 8;
+        break;
+
+    case AUD_FMT_S16:
+        wfx->wBitsPerSample = 16;
+        wfx->nAvgBytesPerSec <<= 1;
+        wfx->nBlockAlign <<= 1;
+        break;
+
+    case AUD_FMT_U16:
+        wfx->wBitsPerSample = 16;
+        wfx->nAvgBytesPerSec <<= 1;
+        wfx->nBlockAlign <<= 1;
+        break;
+
+    default:
+        dolog ("Internal logic error: Bad audio format %d\n", as->freq);
+        return -1;
+    }
+
+    return 0;
+}
+
+static int waveformat_to_audio_settings (WAVEFORMATEX *wfx, audsettings_t *as)
+{
+    if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
+        dolog ("Invalid wave format, tag is not PCM, but %d\n",
+               wfx->wFormatTag);
+        return -1;
+    }
+
+    if (!wfx->nSamplesPerSec) {
+        dolog ("Invalid wave format, frequency is zero\n");
+        return -1;
+    }
+    as->freq = wfx->nSamplesPerSec;
+
+    switch (wfx->nChannels) {
+    case 1:
+        as->nchannels = 1;
+        break;
+
+    case 2:
+        as->nchannels = 2;
+        break;
+
+    default:
+        dolog (
+            "Invalid wave format, number of channels is not 1 or 2, but %d\n",
+            wfx->nChannels
+            );
+        return -1;
+    }
+
+    switch (wfx->wBitsPerSample) {
+    case 8:
+        as->fmt = AUD_FMT_U8;
+        break;
+
+    case 16:
+        as->fmt = AUD_FMT_S16;
+        break;
+
+    default:
+        dolog ("Invalid wave format, bits per sample is not 8 or 16, but %d\n",
+               wfx->wBitsPerSample);
+        return -1;
+    }
+
+    return 0;
+}
+
+#include "dsound_template.h"
+#define DSBTYPE_IN
+#include "dsound_template.h"
+#undef DSBTYPE_IN
+
+static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp)
+{
+    HRESULT hr;
+    int i;
+
+    for (i = 0; i < conf.getstatus_retries; ++i) {
+        hr = IDirectSoundBuffer_GetStatus (dsb, statusp);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not get playback buffer status\n");
+            return -1;
+        }
+
+        if (*statusp & DSERR_BUFFERLOST) {
+            if (dsound_restore_out (dsb)) {
+                return -1;
+            }
+            continue;
+        }
+        break;
+    }
+
+    return 0;
+}
+
+static int dsound_get_status_in (LPDIRECTSOUNDCAPTUREBUFFER dscb,
+                                 DWORD *statusp)
+{
+    HRESULT hr;
+
+    hr = IDirectSoundCaptureBuffer_GetStatus (dscb, statusp);
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not get capture buffer status\n");
+        return -1;
+    }
+
+    return 0;
+}
+
+static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
+{
+    int src_len1 = dst_len;
+    int src_len2 = 0;
+    int pos = hw->rpos + dst_len;
+    st_sample_t *src1 = hw->mix_buf + hw->rpos;
+    st_sample_t *src2 = NULL;
+
+    if (pos > hw->samples) {
+        src_len1 = hw->samples - hw->rpos;
+        src2 = hw->mix_buf;
+        src_len2 = dst_len - src_len1;
+        pos = src_len2;
+    }
+
+    if (src_len1) {
+        hw->clip (dst, src1, src_len1);
+        mixeng_clear (src1, src_len1);
+    }
+
+    if (src_len2) {
+        dst = advance (dst, src_len1 << hw->info.shift);
+        hw->clip (dst, src2, src_len2);
+        mixeng_clear (src2, src_len2);
+    }
+
+    hw->rpos = pos % hw->samples;
+}
+
+static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb)
+{
+    int err;
+    LPVOID p1, p2;
+    DWORD blen1, blen2, len1, len2;
+
+    err = dsound_lock_out (
+        dsb,
+        &hw->info,
+        0,
+        hw->samples << hw->info.shift,
+        &p1, &p2,
+        &blen1, &blen2,
+        1
+        );
+    if (err) {
+        return;
+    }
+
+    len1 = blen1 >> hw->info.shift;
+    len2 = blen2 >> hw->info.shift;
+
+#ifdef DEBUG_DSOUND
+    dolog ("clear %p,%ld,%ld %p,%ld,%ld\n",
+           p1, blen1, len1,
+           p2, blen2, len2);
+#endif
+
+    if (p1 && len1) {
+        audio_pcm_info_clear_buf (&hw->info, p1, len1);
+    }
+
+    if (p2 && len2) {
+        audio_pcm_info_clear_buf (&hw->info, p2, len2);
+    }
+
+    dsound_unlock_out (dsb, p1, p2, blen1, blen2);
+}
+
+static void dsound_close (dsound *s)
+{
+    HRESULT hr;
+
+    if (s->dsound_primary_buffer) {
+        hr = IDirectSoundBuffer_Release (s->dsound_primary_buffer);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not release primary buffer\n");
+        }
+        s->dsound_primary_buffer = NULL;
+    }
+}
+
+static int dsound_open (dsound *s)
+{
+    int err;
+    HRESULT hr;
+    WAVEFORMATEX wfx;
+    DSBUFFERDESC dsbd;
+    HWND hwnd;
+
+    hwnd = GetForegroundWindow ();
+    hr = IDirectSound_SetCooperativeLevel (
+        s->dsound,
+        hwnd,
+        DSSCL_PRIORITY
+        );
+
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not set cooperative level for window %p\n",
+                       hwnd);
+        return -1;
+    }
+
+    if (!conf.set_primary) {
+        return 0;
+    }
+
+    err = waveformat_from_audio_settings (&wfx, &conf.settings);
+    if (err) {
+        return -1;
+    }
+
+    memset (&dsbd, 0, sizeof (dsbd));
+    dsbd.dwSize = sizeof (dsbd);
+    dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
+    dsbd.dwBufferBytes = 0;
+    dsbd.lpwfxFormat = NULL;
+
+    hr = IDirectSound_CreateSoundBuffer (
+        s->dsound,
+        &dsbd,
+        &s->dsound_primary_buffer,
+        NULL
+        );
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not create primary playback buffer\n");
+        return -1;
+    }
+
+    hr = IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx);
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not set primary playback buffer format\n");
+    }
+
+    hr = IDirectSoundBuffer_GetFormat (
+        s->dsound_primary_buffer,
+        &wfx,
+        sizeof (wfx),
+        NULL
+        );
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not get primary playback buffer format\n");
+        goto fail0;
+    }
+
+#ifdef DEBUG_DSOUND
+    dolog ("Primary\n");
+    print_wave_format (&wfx);
+#endif
+
+    err = waveformat_to_audio_settings (&wfx, &s->settings);
+    if (err) {
+        goto fail0;
+    }
+
+    return 0;
+
+ fail0:
+    dsound_close (s);
+    return -1;
+}
+
+static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+    HRESULT hr;
+    DWORD status;
+    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
+    LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
+
+    if (!dsb) {
+        dolog ("Attempt to control voice without a buffer\n");
+        return 0;
+    }
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        if (dsound_get_status_out (dsb, &status)) {
+            return -1;
+        }
+
+        if (status & DSBSTATUS_PLAYING) {
+            dolog ("warning: Voice is already playing\n");
+            return 0;
+        }
+
+        dsound_clear_sample (hw, dsb);
+
+        hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not start playing buffer\n");
+            return -1;
+        }
+        break;
+
+    case VOICE_DISABLE:
+        if (dsound_get_status_out (dsb, &status)) {
+            return -1;
+        }
+
+        if (status & DSBSTATUS_PLAYING) {
+            hr = IDirectSoundBuffer_Stop (dsb);
+            if (FAILED (hr)) {
+                dsound_logerr (hr, "Could not stop playing buffer\n");
+                return -1;
+            }
+        }
+        else {
+            dolog ("warning: Voice is not playing\n");
+        }
+        break;
+    }
+    return 0;
+}
+
+static int dsound_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int dsound_run_out (HWVoiceOut *hw)
+{
+    int err;
+    HRESULT hr;
+    DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
+    LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
+    int live, len, hwshift;
+    DWORD blen1, blen2;
+    DWORD len1, len2;
+    DWORD decr;
+    DWORD wpos, ppos, old_pos;
+    LPVOID p1, p2;
+    int bufsize;
+
+    if (!dsb) {
+        dolog ("Attempt to run empty with playback buffer\n");
+        return 0;
+    }
+
+    hwshift = hw->info.shift;
+    bufsize = hw->samples << hwshift;
+
+    live = audio_pcm_hw_get_live_out (hw);
+
+    hr = IDirectSoundBuffer_GetCurrentPosition (
+        dsb,
+        &ppos,
+        ds->first_time ? &wpos : NULL
+        );
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not get playback buffer position\n");
+        return 0;
+    }
+
+    len = live << hwshift;
+
+    if (ds->first_time) {
+        if (conf.latency_millis) {
+            DWORD cur_blat;
+
+            cur_blat = audio_ring_dist (wpos, ppos, bufsize);
+            ds->first_time = 0;
+            old_pos = wpos;
+            old_pos +=
+                millis_to_bytes (&hw->info, conf.latency_millis) - cur_blat;
+            old_pos %= bufsize;
+            old_pos &= ~hw->info.align;
+        }
+        else {
+            old_pos = wpos;
+        }
+#ifdef DEBUG_DSOUND
+        ds->played = 0;
+        ds->mixed = 0;
+#endif
+    }
+    else {
+        if (ds->old_pos == ppos) {
+#ifdef DEBUG_DSOUND
+            dolog ("old_pos == ppos\n");
+#endif
+            return 0;
+        }
+
+#ifdef DEBUG_DSOUND
+        ds->played += audio_ring_dist (ds->old_pos, ppos, hw->bufsize);
+#endif
+        old_pos = ds->old_pos;
+    }
+
+    if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
+        len = ppos - old_pos;
+    }
+    else {
+        if ((old_pos > ppos) && ((old_pos + len) > (ppos + bufsize))) {
+            len = bufsize - old_pos + ppos;
+        }
+    }
+
+    if (audio_bug (AUDIO_FUNC, len < 0 || len > bufsize)) {
+        dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n",
+               len, bufsize, old_pos, ppos);
+        return 0;
+    }
+
+    len &= ~hw->info.align;
+    if (!len) {
+        return 0;
+    }
+
+#ifdef DEBUG_DSOUND
+    ds->old_ppos = ppos;
+#endif
+    err = dsound_lock_out (
+        dsb,
+        &hw->info,
+        old_pos,
+        len,
+        &p1, &p2,
+        &blen1, &blen2,
+        0
+        );
+    if (err) {
+        return 0;
+    }
+
+    len1 = blen1 >> hwshift;
+    len2 = blen2 >> hwshift;
+    decr = len1 + len2;
+
+    if (p1 && len1) {
+        dsound_write_sample (hw, p1, len1);
+    }
+
+    if (p2 && len2) {
+        dsound_write_sample (hw, p2, len2);
+    }
+
+    dsound_unlock_out (dsb, p1, p2, blen1, blen2);
+    ds->old_pos = (old_pos + (decr << hwshift)) % bufsize;
+
+#ifdef DEBUG_DSOUND
+    ds->mixed += decr << hwshift;
+
+    dolog ("played %lu mixed %lu diff %ld sec %f\n",
+           ds->played,
+           ds->mixed,
+           ds->mixed - ds->played,
+           abs (ds->mixed - ds->played) / (double) hw->info.bytes_per_second);
+#endif
+    return decr;
+}
+
+static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+    HRESULT hr;
+    DWORD status;
+    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
+    LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
+
+    if (!dscb) {
+        dolog ("Attempt to control capture voice without a buffer\n");
+        return -1;
+    }
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        if (dsound_get_status_in (dscb, &status)) {
+            return -1;
+        }
+
+        if (status & DSCBSTATUS_CAPTURING) {
+            dolog ("warning: Voice is already capturing\n");
+            return 0;
+        }
+
+        /* clear ?? */
+
+        hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not start capturing\n");
+            return -1;
+        }
+        break;
+
+    case VOICE_DISABLE:
+        if (dsound_get_status_in (dscb, &status)) {
+            return -1;
+        }
+
+        if (status & DSCBSTATUS_CAPTURING) {
+            hr = IDirectSoundCaptureBuffer_Stop (dscb);
+            if (FAILED (hr)) {
+                dsound_logerr (hr, "Could not stop capturing\n");
+                return -1;
+            }
+        }
+        else {
+            dolog ("warning: Voice is not capturing\n");
+        }
+        break;
+    }
+    return 0;
+}
+
+static int dsound_read (SWVoiceIn *sw, void *buf, int len)
+{
+    return audio_pcm_sw_read (sw, buf, len);
+}
+
+static int dsound_run_in (HWVoiceIn *hw)
+{
+    int err;
+    HRESULT hr;
+    DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
+    LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
+    int live, len, dead;
+    DWORD blen1, blen2;
+    DWORD len1, len2;
+    DWORD decr;
+    DWORD cpos, rpos;
+    LPVOID p1, p2;
+    int hwshift;
+
+    if (!dscb) {
+        dolog ("Attempt to run without capture buffer\n");
+        return 0;
+    }
+
+    hwshift = hw->info.shift;
+
+    live = audio_pcm_hw_get_live_in (hw);
+    dead = hw->samples - live;
+    if (!dead) {
+        return 0;
+    }
+
+    hr = IDirectSoundCaptureBuffer_GetCurrentPosition (
+        dscb,
+        &cpos,
+        ds->first_time ? &rpos : NULL
+        );
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not get capture buffer position\n");
+        return 0;
+    }
+
+    if (ds->first_time) {
+        ds->first_time = 0;
+        if (rpos & hw->info.align) {
+            ldebug ("warning: Misaligned capture read position %ld(%d)\n",
+                    rpos, hw->info.align);
+        }
+        hw->wpos = rpos >> hwshift;
+    }
+
+    if (cpos & hw->info.align) {
+        ldebug ("warning: Misaligned capture position %ld(%d)\n",
+                cpos, hw->info.align);
+    }
+    cpos >>= hwshift;
+
+    len = audio_ring_dist (cpos, hw->wpos, hw->samples);
+    if (!len) {
+        return 0;
+    }
+    len = audio_MIN (len, dead);
+
+    err = dsound_lock_in (
+        dscb,
+        &hw->info,
+        hw->wpos << hwshift,
+        len << hwshift,
+        &p1,
+        &p2,
+        &blen1,
+        &blen2,
+        0
+        );
+    if (err) {
+        return 0;
+    }
+
+    len1 = blen1 >> hwshift;
+    len2 = blen2 >> hwshift;
+    decr = len1 + len2;
+
+    if (p1 && len1) {
+        hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
+    }
+
+    if (p2 && len2) {
+        hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
+    }
+
+    dsound_unlock_in (dscb, p1, p2, blen1, blen2);
+    hw->wpos = (hw->wpos + decr) % hw->samples;
+    return decr;
+}
+
+static void dsound_audio_fini (void *opaque)
+{
+    HRESULT hr;
+    dsound *s = opaque;
+
+    if (!s->dsound) {
+        return;
+    }
+
+    hr = IDirectSound_Release (s->dsound);
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not release DirectSound\n");
+    }
+    s->dsound = NULL;
+
+    if (!s->dsound_capture) {
+        return;
+    }
+
+    hr = IDirectSoundCapture_Release (s->dsound_capture);
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not release DirectSoundCapture\n");
+    }
+    s->dsound_capture = NULL;
+}
+
+static void *dsound_audio_init (void)
+{
+    int err;
+    HRESULT hr;
+    dsound *s = &glob_dsound;
+
+    hr = CoInitialize (NULL);
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not initialize COM\n");
+        return NULL;
+    }
+
+    hr = CoCreateInstance (
+        &CLSID_DirectSound,
+        NULL,
+        CLSCTX_ALL,
+        &IID_IDirectSound,
+        (void **) &s->dsound
+        );
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not create DirectSound instance\n");
+        return NULL;
+    }
+
+    hr = IDirectSound_Initialize (s->dsound, NULL);
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not initialize DirectSound\n");
+        return NULL;
+    }
+
+    hr = CoCreateInstance (
+        &CLSID_DirectSoundCapture,
+        NULL,
+        CLSCTX_ALL,
+        &IID_IDirectSoundCapture,
+        (void **) &s->dsound_capture
+        );
+    if (FAILED (hr)) {
+        dsound_logerr (hr, "Could not create DirectSoundCapture instance\n");
+    }
+    else {
+        hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL);
+        if (FAILED (hr)) {
+            dsound_logerr (hr, "Could not initialize DirectSoundCapture\n");
+
+            hr = IDirectSoundCapture_Release (s->dsound_capture);
+            if (FAILED (hr)) {
+                dsound_logerr (hr, "Could not release DirectSoundCapture\n");
+            }
+            s->dsound_capture = NULL;
+        }
+    }
+
+    err = dsound_open (s);
+    if (err) {
+        dsound_audio_fini (s);
+        return NULL;
+    }
+
+    return s;
+}
+
+static struct audio_option dsound_options[] = {
+    {"LOCK_RETRIES", AUD_OPT_INT, &conf.lock_retries,
+     "Number of times to attempt locking the buffer", NULL, 0},
+    {"RESTOURE_RETRIES", AUD_OPT_INT, &conf.restore_retries,
+     "Number of times to attempt restoring the buffer", NULL, 0},
+    {"GETSTATUS_RETRIES", AUD_OPT_INT, &conf.getstatus_retries,
+     "Number of times to attempt getting status of the buffer", NULL, 0},
+    {"SET_PRIMARY", AUD_OPT_BOOL, &conf.set_primary,
+     "Set the parameters of primary buffer", NULL, 0},
+    {"LATENCY_MILLIS", AUD_OPT_INT, &conf.latency_millis,
+     "(undocumented)", NULL, 0},
+    {"PRIMARY_FREQ", AUD_OPT_INT, &conf.settings.freq,
+     "Primary buffer frequency", NULL, 0},
+    {"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels,
+     "Primary buffer number of channels (1 - mono, 2 - stereo)", NULL, 0},
+    {"PRIMARY_FMT", AUD_OPT_FMT, &conf.settings.fmt,
+     "Primary buffer format", NULL, 0},
+    {"BUFSIZE_OUT", AUD_OPT_INT, &conf.bufsize_out,
+     "(undocumented)", NULL, 0},
+    {"BUFSIZE_IN", AUD_OPT_INT, &conf.bufsize_in,
+     "(undocumented)", NULL, 0},
+    {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+static struct audio_pcm_ops dsound_pcm_ops = {
+    dsound_init_out,
+    dsound_fini_out,
+    dsound_run_out,
+    dsound_write,
+    dsound_ctl_out,
+
+    dsound_init_in,
+    dsound_fini_in,
+    dsound_run_in,
+    dsound_read,
+    dsound_ctl_in
+};
+
+struct audio_driver dsound_audio_driver = {
+    INIT_FIELD (name           = ) "dsound",
+    INIT_FIELD (descr          = )
+    "DirectSound http://wikipedia.org/wiki/DirectSound",
+    INIT_FIELD (options        = ) dsound_options,
+    INIT_FIELD (init           = ) dsound_audio_init,
+    INIT_FIELD (fini           = ) dsound_audio_fini,
+    INIT_FIELD (pcm_ops        = ) &dsound_pcm_ops,
+    INIT_FIELD (can_be_default = ) 1,
+    INIT_FIELD (max_voices_out = ) INT_MAX,
+    INIT_FIELD (max_voices_in  = ) 1,
+    INIT_FIELD (voice_size_out = ) sizeof (DSoundVoiceOut),
+    INIT_FIELD (voice_size_in  = ) sizeof (DSoundVoiceIn)
+};
index 7b79026..072d8a8 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * QEMU FMOD audio output driver
- * 
- * Copyright (c) 2004 Vassili Karpov (malc)
- * 
+ * QEMU FMOD audio driver
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
  * 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
 #include <fmod_errors.h>
 #include "vl.h"
 
-#include "audio/audio_int.h"
+#define AUDIO_CAP "fmod"
+#include "audio_int.h"
 
-typedef struct FMODVoice {
-    HWVoice hw;
+typedef struct FMODVoiceOut {
+    HWVoiceOut hw;
     unsigned int old_pos;
     FSOUND_SAMPLE *fmod_sample;
     int channel;
-} FMODVoice;
-
-#define dolog(...) AUD_log ("fmod", __VA_ARGS__)
-#ifdef DEBUG
-#define ldebug(...) dolog (__VA_ARGS__)
-#else
-#define ldebug(...)
-#endif
+} FMODVoiceOut;
 
-#define QC_FMOD_DRV "QEMU_FMOD_DRV"
-#define QC_FMOD_FREQ "QEMU_FMOD_FREQ"
-#define QC_FMOD_SAMPLES "QEMU_FMOD_SAMPLES"
-#define QC_FMOD_CHANNELS "QEMU_FMOD_CHANNELS"
-#define QC_FMOD_BUFSIZE "QEMU_FMOD_BUFSIZE"
-#define QC_FMOD_THRESHOLD "QEMU_FMOD_THRESHOLD"
+typedef struct FMODVoiceIn {
+    HWVoiceIn hw;
+    FSOUND_SAMPLE *fmod_sample;
+} FMODVoiceIn;
 
 static struct {
+    const char *drvname;
     int nb_samples;
     int freq;
     int nb_channels;
     int bufsize;
     int threshold;
+    int broken_adc;
 } conf = {
-    2048,
+    NULL,
+    2048 * 2,
     44100,
-    1,
+    2,
+    0,
     0,
-    128
+    0
 };
 
-#define errstr() FMOD_ErrorString (FSOUND_GetError ())
+static void GCC_FMT_ATTR (1, 2) fmod_logerr (const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
 
-static int fmod_hw_write (SWVoice *sw, void *buf, int len)
+    AUD_log (AUDIO_CAP, "Reason: %s\n",
+             FMOD_ErrorString (FSOUND_GetError ()));
+}
+
+static void GCC_FMT_ATTR (2, 3) fmod_logerr2 (
+    const char *typ,
+    const char *fmt,
+    ...
+    )
 {
-    return pcm_hw_write (sw, buf, len);
+    va_list ap;
+
+    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n",
+             FMOD_ErrorString (FSOUND_GetError ()));
 }
 
-static void fmod_clear_sample (FMODVoice *fmd)
+static int fmod_write (SWVoiceOut *sw, void *buf, int len)
 {
-    HWVoice *hw = &fmd->hw;
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static void fmod_clear_sample (FMODVoiceOut *fmd)
+{
+    HWVoiceOut *hw = &fmd->hw;
     int status;
     void *p1 = 0, *p2 = 0;
     unsigned int len1 = 0, len2 = 0;
@@ -79,7 +103,7 @@ static void fmod_clear_sample (FMODVoice *fmd)
     status = FSOUND_Sample_Lock (
         fmd->fmod_sample,
         0,
-        hw->samples << hw->shift,
+        hw->samples << hw->info.shift,
         &p1,
         &p2,
         &len1,
@@ -87,78 +111,88 @@ static void fmod_clear_sample (FMODVoice *fmd)
         );
 
     if (!status) {
-        dolog ("Failed to lock sample\nReason: %s\n", errstr ());
+        fmod_logerr ("Failed to lock sample\n");
         return;
     }
 
-    if ((len1 & hw->align) || (len2 & hw->align)) {
-        dolog ("Locking sample returned unaligned length %d, %d\n",
-               len1, len2);
+    if ((len1 & hw->info.align) || (len2 & hw->info.align)) {
+        dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
+               len1, len2, hw->info.align + 1);
         goto fail;
     }
 
-    if (len1 + len2 != hw->samples << hw->shift) {
-        dolog ("Locking sample returned incomplete length %d, %d\n",
-               len1 + len2, hw->samples << hw->shift);
+    if ((len1 + len2) - (hw->samples << hw->info.shift)) {
+        dolog ("Lock returned incomplete length %d, %d\n",
+               len1 + len2, hw->samples << hw->info.shift);
         goto fail;
     }
-    pcm_hw_clear (hw, p1, hw->samples);
+
+    audio_pcm_info_clear_buf (&hw->info, p1, hw->samples);
 
  fail:
     status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2);
     if (!status) {
-        dolog ("Failed to unlock sample\nReason: %s\n", errstr ());
+        fmod_logerr ("Failed to unlock sample\n");
     }
 }
 
-static int fmod_write_sample (HWVoice *hw, uint8_t *dst, st_sample_t *src,
-                              int src_size, int src_pos, int dst_len)
+static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
 {
-    int src_len1 = dst_len, src_len2 = 0, pos = src_pos + dst_len;
-    st_sample_t *src1 = src + src_pos, *src2 = 0;
-
-    if (src_pos + dst_len > src_size) {
-        src_len1 = src_size - src_pos;
-        src2 = src;
+    int src_len1 = dst_len;
+    int src_len2 = 0;
+    int pos = hw->rpos + dst_len;
+    st_sample_t *src1 = hw->mix_buf + hw->rpos;
+    st_sample_t *src2 = NULL;
+
+    if (pos > hw->samples) {
+        src_len1 = hw->samples - hw->rpos;
+        src2 = hw->mix_buf;
         src_len2 = dst_len - src_len1;
         pos = src_len2;
     }
 
     if (src_len1) {
         hw->clip (dst, src1, src_len1);
-        memset (src1, 0, src_len1 * sizeof (st_sample_t));
-        advance (dst, src_len1);
+        mixeng_clear (src1, src_len1);
     }
 
     if (src_len2) {
+        dst = advance (dst, src_len1 << hw->info.shift);
         hw->clip (dst, src2, src_len2);
-        memset (src2, 0, src_len2 * sizeof (st_sample_t));
+        mixeng_clear (src2, src_len2);
     }
-    return pos;
+
+    hw->rpos = pos % hw->samples;
 }
 
-static int fmod_unlock_sample (FMODVoice *fmd, void *p1, void *p2,
+static int fmod_unlock_sample (FSOUND_SAMPLE *sample, void *p1, void *p2,
                                unsigned int blen1, unsigned int blen2)
 {
-    int status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, blen1, blen2);
+    int status = FSOUND_Sample_Unlock (sample, p1, p2, blen1, blen2);
     if (!status) {
-        dolog ("Failed to unlock sample\nReason: %s\n", errstr ());
+        fmod_logerr ("Failed to unlock sample\n");
         return -1;
     }
     return 0;
 }
 
-static int fmod_lock_sample (FMODVoice *fmd, int pos, int len,
-                             void **p1, void **p2,
-                             unsigned int *blen1, unsigned int *blen2)
+static int fmod_lock_sample (
+    FSOUND_SAMPLE *sample,
+    struct audio_pcm_info *info,
+    int pos,
+    int len,
+    void **p1,
+    void **p2,
+    unsigned int *blen1,
+    unsigned int *blen2
+    )
 {
-    HWVoice *hw = &fmd->hw;
     int status;
 
     status = FSOUND_Sample_Lock (
-        fmd->fmod_sample,
-        pos << hw->shift,
-        len << hw->shift,
+        sample,
+        pos << info->shift,
+        len << info->shift,
         p1,
         p2,
         blen1,
@@ -166,89 +200,117 @@ static int fmod_lock_sample (FMODVoice *fmd, int pos, int len,
         );
 
     if (!status) {
-        dolog ("Failed to lock sample\nReason: %s\n", errstr ());
+        fmod_logerr ("Failed to lock sample\n");
         return -1;
     }
 
-    if ((*blen1 & hw->align) || (*blen2 & hw->align)) {
-        dolog ("Locking sample returned unaligned length %d, %d\n",
-               *blen1, *blen2);
-        fmod_unlock_sample (fmd, *p1, *p2, *blen1, *blen2);
+    if ((*blen1 & info->align) || (*blen2 & info->align)) {
+        dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
+               *blen1, *blen2, info->align + 1);
+
+        fmod_unlock_sample (sample, *p1, *p2, *blen1, *blen2);
+
+        *p1 = NULL - 1;
+        *p2 = NULL - 1;
+        *blen1 = ~0U;
+        *blen2 = ~0U;
         return -1;
     }
+
+    if (!*p1 && *blen1) {
+        dolog ("warning: !p1 && blen1=%d\n", *blen1);
+        *blen1 = 0;
+    }
+
+    if (!p2 && *blen2) {
+        dolog ("warning: !p2 && blen2=%d\n", *blen2);
+        *blen2 = 0;
+    }
+
     return 0;
 }
 
-static void fmod_hw_run (HWVoice *hw)
+static int fmod_run_out (HWVoiceOut *hw)
 {
-    FMODVoice *fmd = (FMODVoice *) hw;
-    int rpos, live, decr;
+    FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
+    int live, decr;
     void *p1 = 0, *p2 = 0;
     unsigned int blen1 = 0, blen2 = 0;
     unsigned int len1 = 0, len2 = 0;
-    int nb_active;
+    int nb_live;
 
-    live = pcm_hw_get_live2 (hw, &nb_active);
-    if (live <= 0) {
-        return;
+    live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
+    if (!live) {
+        return 0;
     }
 
     if (!hw->pending_disable
-        && nb_active
-        && conf.threshold
-        && live <= conf.threshold) {
-        ldebug ("live=%d nb_active=%d\n", live, nb_active);
-        return;
+        && nb_live
+        && (conf.threshold && live <= conf.threshold)) {
+        ldebug ("live=%d nb_live=%d\n", live, nb_live);
+        return 0;
     }
 
     decr = live;
 
-#if 1
     if (fmd->channel >= 0) {
-        int pos2 = (fmd->old_pos + decr) % hw->samples;
-        int pos = FSOUND_GetCurrentPosition (fmd->channel);
+        int len = decr;
+        int old_pos = fmd->old_pos;
+        int ppos = FSOUND_GetCurrentPosition (fmd->channel);
 
-        if (fmd->old_pos < pos && pos2 >= pos) {
-            decr = pos - fmd->old_pos - (pos2 == pos) - 1;
+        if (ppos == old_pos || !ppos) {
+            return 0;
         }
-        else if (fmd->old_pos > pos && pos2 >= pos && pos2 < fmd->old_pos) {
-            decr = (hw->samples - fmd->old_pos) + pos - (pos2 == pos) - 1;
+
+        if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
+            len = ppos - old_pos;
+        }
+        else {
+            if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->samples))) {
+                len = hw->samples - old_pos + ppos;
+            }
+        }
+        decr = len;
+
+        if (audio_bug (AUDIO_FUNC, decr < 0)) {
+            dolog ("decr=%d live=%d ppos=%d old_pos=%d len=%d\n",
+                   decr, live, ppos, old_pos, len);
+            return 0;
         }
-/*         ldebug ("pos=%d pos2=%d old=%d live=%d decr=%d\n", */
-/*                 pos, pos2, fmd->old_pos, live, decr); */
     }
-#endif
 
-    if (decr <= 0) {
-        return;
+
+    if (!decr) {
+        return 0;
     }
 
-    if (fmod_lock_sample (fmd, fmd->old_pos, decr, &p1, &p2, &blen1, &blen2)) {
-        return;
+    if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
+                          fmd->old_pos, decr,
+                          &p1, &p2,
+                          &blen1, &blen2)) {
+        return 0;
     }
 
-    len1 = blen1 >> hw->shift;
-    len2 = blen2 >> hw->shift;
+    len1 = blen1 >> hw->info.shift;
+    len2 = blen2 >> hw->info.shift;
     ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2);
     decr = len1 + len2;
-    rpos = hw->rpos;
 
-    if (len1) {
-        rpos = fmod_write_sample (hw, p1, hw->mix_buf, hw->samples, rpos, len1);
+    if (p1 && len1) {
+        fmod_write_sample (hw, p1, len1);
     }
 
-    if (len2) {
-        rpos = fmod_write_sample (hw, p2, hw->mix_buf, hw->samples, rpos, len2);
+    if (p2 && len2) {
+        fmod_write_sample (hw, p2, len2);
     }
 
-    fmod_unlock_sample (fmd, p1, p2, blen1, blen2);
+    fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
 
-    pcm_hw_dec_live (hw, decr);
-    hw->rpos = rpos % hw->samples;
     fmd->old_pos = (fmd->old_pos + decr) % hw->samples;
+    return decr;
 }
 
-static int AUD_to_fmodfmt (audfmt_e fmt, int stereo)
+static int aud_to_fmodfmt (audfmt_e fmt, int stereo)
 {
     int mode = FSOUND_LOOP_NORMAL;
 
@@ -270,16 +332,19 @@ static int AUD_to_fmodfmt (audfmt_e fmt, int stereo)
         break;
 
     default:
-        dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
-        exit (EXIT_FAILURE);
+        dolog ("Internal logic error: Bad audio format %d\n", fmt);
+#ifdef DEBUG_FMOD
+        abort ();
+#endif
+        mode |= FSOUND_8BITS;
     }
     mode |= stereo ? FSOUND_STEREO : FSOUND_MONO;
     return mode;
 }
 
-static void fmod_hw_fini (HWVoice *hw)
+static void fmod_fini_out (HWVoiceOut *hw)
 {
-    FMODVoice *fmd = (FMODVoice *) hw;
+    FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
 
     if (fmd->fmod_sample) {
         FSOUND_Sample_Free (fmd->fmod_sample);
@@ -291,69 +356,160 @@ static void fmod_hw_fini (HWVoice *hw)
     }
 }
 
-static int fmod_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
+static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as)
 {
     int bits16, mode, channel;
-    FMODVoice *fmd = (FMODVoice *) hw;
+    FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
 
-    mode = AUD_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0);
+    mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
     fmd->fmod_sample = FSOUND_Sample_Alloc (
         FSOUND_FREE,            /* index */
         conf.nb_samples,        /* length */
         mode,                   /* mode */
-        freq,                   /* freq */
+        as->freq,               /* freq */
         255,                    /* volume */
         128,                    /* pan */
         255                     /* priority */
         );
 
     if (!fmd->fmod_sample) {
-        dolog ("Failed to allocate FMOD sample\nReason: %s\n", errstr ());
+        fmod_logerr2 ("DAC", "Failed to allocate FMOD sample\n");
         return -1;
     }
 
     channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1);
     if (channel < 0) {
-        dolog ("Failed to start playing sound\nReason: %s\n", errstr ());
+        fmod_logerr2 ("DAC", "Failed to start playing sound\n");
         FSOUND_Sample_Free (fmd->fmod_sample);
         return -1;
     }
     fmd->channel = channel;
 
-    hw->freq = freq;
-    hw->fmt = fmt;
-    hw->nchannels = nchannels;
-    bits16 = fmt == AUD_FMT_U16 || fmt == AUD_FMT_S16;
-    hw->bufsize = conf.nb_samples << (nchannels == 2) << bits16;
+    /* FMOD always operates on little endian frames? */
+    audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0));
+    bits16 = (mode & FSOUND_16BITS) != 0;
+    hw->samples = conf.nb_samples;
     return 0;
 }
 
-static int fmod_hw_ctl (HWVoice *hw, int cmd, ...)
+static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...)
 {
     int status;
-    FMODVoice *fmd = (FMODVoice *) hw;
+    FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
 
     switch (cmd) {
     case VOICE_ENABLE:
         fmod_clear_sample (fmd);
         status = FSOUND_SetPaused (fmd->channel, 0);
         if (!status) {
-            dolog ("Failed to resume channel %d\nReason: %s\n",
-                   fmd->channel, errstr ());
+            fmod_logerr ("Failed to resume channel %d\n", fmd->channel);
         }
         break;
 
     case VOICE_DISABLE:
         status = FSOUND_SetPaused (fmd->channel, 1);
         if (!status) {
-            dolog ("Failed to pause channel %d\nReason: %s\n",
-                   fmd->channel, errstr ());
+            fmod_logerr ("Failed to pause channel %d\n", fmd->channel);
         }
         break;
     }
     return 0;
 }
 
+static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as)
+{
+    int bits16, mode;
+    FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
+
+    if (conf.broken_adc) {
+        return -1;
+    }
+
+    mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
+    fmd->fmod_sample = FSOUND_Sample_Alloc (
+        FSOUND_FREE,            /* index */
+        conf.nb_samples,        /* length */
+        mode,                   /* mode */
+        as->freq,               /* freq */
+        255,                    /* volume */
+        128,                    /* pan */
+        255                     /* priority */
+        );
+
+    if (!fmd->fmod_sample) {
+        fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n");
+        return -1;
+    }
+
+    /* FMOD always operates on little endian frames? */
+    audio_pcm_init_info (&hw->info, as, audio_need_to_swap_endian (0));
+    bits16 = (mode & FSOUND_16BITS) != 0;
+    hw->samples = conf.nb_samples;
+    return 0;
+}
+
+static void fmod_fini_in (HWVoiceIn *hw)
+{
+    FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
+
+    if (fmd->fmod_sample) {
+        FSOUND_Record_Stop ();
+        FSOUND_Sample_Free (fmd->fmod_sample);
+        fmd->fmod_sample = 0;
+    }
+}
+
+static int fmod_run_in (HWVoiceIn *hw)
+{
+    FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
+    int hwshift = hw->info.shift;
+    int live, dead, new_pos, len;
+    unsigned int blen1 = 0, blen2 = 0;
+    unsigned int len1, len2;
+    unsigned int decr;
+    void *p1, *p2;
+
+    live = audio_pcm_hw_get_live_in (hw);
+    dead = hw->samples - live;
+    if (!dead) {
+        return 0;
+    }
+
+    new_pos = FSOUND_Record_GetPosition ();
+    if (new_pos < 0) {
+        fmod_logerr ("Could not get recording position\n");
+        return 0;
+    }
+
+    len = audio_ring_dist (new_pos,  hw->wpos, hw->samples);
+    if (!len) {
+        return 0;
+    }
+    len = audio_MIN (len, dead);
+
+    if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
+                          hw->wpos, len,
+                          &p1, &p2,
+                          &blen1, &blen2)) {
+        return 0;
+    }
+
+    len1 = blen1 >> hwshift;
+    len2 = blen2 >> hwshift;
+    decr = len1 + len2;
+
+    if (p1 && blen1) {
+        hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
+    }
+    if (p2 && len2) {
+        hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
+    }
+
+    fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
+    hw->wpos = (hw->wpos + decr) % hw->samples;
+    return decr;
+}
+
 static struct {
     const char *name;
     int type;
@@ -378,16 +534,16 @@ static struct {
     {"ps2", FSOUND_OUTPUT_PS2},
     {"gcube", FSOUND_OUTPUT_GC},
 #endif
-    {"nort", FSOUND_OUTPUT_NOSOUND_NONREALTIME}
+    {"none-realtime", FSOUND_OUTPUT_NOSOUND_NONREALTIME}
 };
 
 static void *fmod_audio_init (void)
 {
-    int i;
+    size_t i;
     double ver;
     int status;
     int output_type = -1;
-    const char *drv = audio_get_conf_str (QC_FMOD_DRV, NULL);
+    const char *drv = conf.drvname;
 
     ver = FSOUND_GetVersion ();
     if (ver < FMOD_VERSION) {
@@ -395,6 +551,14 @@ static void *fmod_audio_init (void)
         return NULL;
     }
 
+#ifdef __linux__
+    if (ver < 3.75) {
+        dolog ("FMOD before 3.75 has bug preventing ADC from working\n"
+               "ADC will be disabled.\n");
+        conf.broken_adc = 1;
+    }
+#endif
+
     if (drv) {
         int found = 0;
         for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
@@ -405,65 +569,115 @@ static void *fmod_audio_init (void)
             }
         }
         if (!found) {
-            dolog ("Unknown FMOD output driver `%s'\n", drv);
+            dolog ("Unknown FMOD driver `%s'\n", drv);
+            dolog ("Valid drivers:\n");
+            for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+                dolog ("  %s\n", drvtab[i].name);
+            }
         }
     }
 
     if (output_type != -1) {
         status = FSOUND_SetOutput (output_type);
         if (!status) {
-            dolog ("FSOUND_SetOutput(%d) failed\nReason: %s\n",
-                   output_type, errstr ());
+            fmod_logerr ("FSOUND_SetOutput(%d) failed\n", output_type);
             return NULL;
         }
     }
 
-    conf.freq = audio_get_conf_int (QC_FMOD_FREQ, conf.freq);
-    conf.nb_samples = audio_get_conf_int (QC_FMOD_SAMPLES, conf.nb_samples);
-    conf.nb_channels =
-        audio_get_conf_int (QC_FMOD_CHANNELS,
-                            (audio_state.nb_hw_voices > 1
-                             ? audio_state.nb_hw_voices
-                             : conf.nb_channels));
-    conf.bufsize = audio_get_conf_int (QC_FMOD_BUFSIZE, conf.bufsize);
-    conf.threshold = audio_get_conf_int (QC_FMOD_THRESHOLD, conf.threshold);
-
     if (conf.bufsize) {
         status = FSOUND_SetBufferSize (conf.bufsize);
         if (!status) {
-            dolog ("FSOUND_SetBufferSize (%d) failed\nReason: %s\n",
-                   conf.bufsize, errstr ());
+            fmod_logerr ("FSOUND_SetBufferSize (%d) failed\n", conf.bufsize);
         }
     }
 
     status = FSOUND_Init (conf.freq, conf.nb_channels, 0);
     if (!status) {
-        dolog ("FSOUND_Init failed\nReason: %s\n", errstr ());
+        fmod_logerr ("FSOUND_Init failed\n");
         return NULL;
     }
 
     return &conf;
 }
 
+static int fmod_read (SWVoiceIn *sw, void *buf, int size)
+{
+    return audio_pcm_sw_read (sw, buf, size);
+}
+
+static int fmod_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+    int status;
+    FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
+
+    switch (cmd) {
+    case VOICE_ENABLE:
+        status = FSOUND_Record_StartSample (fmd->fmod_sample, 1);
+        if (!status) {
+            fmod_logerr ("Failed to start recording\n");
+        }
+        break;
+
+    case VOICE_DISABLE:
+        status = FSOUND_Record_Stop ();
+        if (!status) {
+            fmod_logerr ("Failed to stop recording\n");
+        }
+        break;
+    }
+    return 0;
+}
+
 static void fmod_audio_fini (void *opaque)
 {
+    (void) opaque;
     FSOUND_Close ();
 }
 
-struct pcm_ops fmod_pcm_ops = {
-    fmod_hw_init,
-    fmod_hw_fini,
-    fmod_hw_run,
-    fmod_hw_write,
-    fmod_hw_ctl
+static struct audio_option fmod_options[] = {
+    {"DRV", AUD_OPT_STR, &conf.drvname,
+     "FMOD driver", NULL, 0},
+    {"FREQ", AUD_OPT_INT, &conf.freq,
+     "Default frequency", NULL, 0},
+    {"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
+     "Buffer size in samples", NULL, 0},
+    {"CHANNELS", AUD_OPT_INT, &conf.nb_channels,
+     "Number of default channels (1 - mono, 2 - stereo)", NULL, 0},
+    {"BUFSIZE", AUD_OPT_INT, &conf.bufsize,
+     "(undocumented)", NULL, 0},
+#if 0
+    {"THRESHOLD", AUD_OPT_INT, &conf.threshold,
+     "(undocumented)"},
+#endif
+
+    {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+static struct audio_pcm_ops fmod_pcm_ops = {
+    fmod_init_out,
+    fmod_fini_out,
+    fmod_run_out,
+    fmod_write,
+    fmod_ctl_out,
+
+    fmod_init_in,
+    fmod_fini_in,
+    fmod_run_in,
+    fmod_read,
+    fmod_ctl_in
 };
 
-struct audio_output_driver fmod_output_driver = {
-    "fmod",
-    fmod_audio_init,
-    fmod_audio_fini,
-    &fmod_pcm_ops,
-    1,
-    INT_MAX,
-    sizeof (FMODVoice)
+struct audio_driver fmod_audio_driver = {
+    INIT_FIELD (name           = ) "fmod",
+    INIT_FIELD (descr          = ) "FMOD 3.xx http://www.fmod.org",
+    INIT_FIELD (options        = ) fmod_options,
+    INIT_FIELD (init           = ) fmod_audio_init,
+    INIT_FIELD (fini           = ) fmod_audio_fini,
+    INIT_FIELD (pcm_ops        = ) &fmod_pcm_ops,
+    INIT_FIELD (can_be_default = ) 1,
+    INIT_FIELD (max_voices_out = ) INT_MAX,
+    INIT_FIELD (max_voices_in  = ) INT_MAX,
+    INIT_FIELD (voice_size_out = ) sizeof (FMODVoiceOut),
+    INIT_FIELD (voice_size_in  = ) sizeof (FMODVoiceIn)
 };
index b0bb412..6308d41 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * QEMU Mixing engine
  *
- * Copyright (c) 2004 Vassili Karpov (malc)
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
  * Copyright (c) 1998 Fabrice Bellard
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * THE SOFTWARE.
  */
 #include "vl.h"
-//#define DEBUG_FP
-#include "audio/mixeng.h"
 
+#define AUDIO_CAP "mixeng"
+#include "audio_int.h"
+
+#define NOVOL
+
+/* 8 bit */
+#define ENDIAN_CONVERSION natural
+#define ENDIAN_CONVERT(v) (v)
+
+/* Signed 8 bit */
 #define IN_T int8_t
-#define IN_MIN CHAR_MIN
-#define IN_MAX CHAR_MAX
+#define IN_MIN SCHAR_MIN
+#define IN_MAX SCHAR_MAX
 #define SIGNED
+#define SHIFT 8
 #include "mixeng_template.h"
 #undef SIGNED
 #undef IN_MAX
 #undef IN_MIN
 #undef IN_T
+#undef SHIFT
 
+/* Unsigned 8 bit */
 #define IN_T uint8_t
 #define IN_MIN 0
 #define IN_MAX UCHAR_MAX
+#define SHIFT 8
 #include "mixeng_template.h"
 #undef IN_MAX
 #undef IN_MIN
 #undef IN_T
+#undef SHIFT
+
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
 
+/* Signed 16 bit */
 #define IN_T int16_t
 #define IN_MIN SHRT_MIN
 #define IN_MAX SHRT_MAX
 #define SIGNED
+#define SHIFT 16
+#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) bswap16 (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
 #undef SIGNED
 #undef IN_MAX
 #undef IN_MIN
 #undef IN_T
+#undef SHIFT
 
 #define IN_T uint16_t
 #define IN_MIN 0
 #define IN_MAX USHRT_MAX
+#define SHIFT 16
+#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) bswap16 (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] = {
+t_sample *mixeng_conv[2][2][2][2] = {
     {
         {
-            conv_uint8_t_to_mono,
-            conv_uint16_t_to_mono
+            {
+                conv_natural_uint8_t_to_mono,
+                conv_natural_uint16_t_to_mono
+            },
+            {
+                conv_natural_uint8_t_to_mono,
+                conv_swap_uint16_t_to_mono
+            }
         },
         {
-            conv_int8_t_to_mono,
-            conv_int16_t_to_mono
+            {
+                conv_natural_int8_t_to_mono,
+                conv_natural_int16_t_to_mono
+            },
+            {
+                conv_natural_int8_t_to_mono,
+                conv_swap_int16_t_to_mono
+            }
         }
     },
     {
         {
-            conv_uint8_t_to_stereo,
-            conv_uint16_t_to_stereo
+            {
+                conv_natural_uint8_t_to_stereo,
+                conv_natural_uint16_t_to_stereo
+            },
+            {
+                conv_natural_uint8_t_to_stereo,
+                conv_swap_uint16_t_to_stereo
+            }
         },
         {
-            conv_int8_t_to_stereo,
-            conv_int16_t_to_stereo
+            {
+                conv_natural_int8_t_to_stereo,
+                conv_natural_int16_t_to_stereo
+            },
+            {
+                conv_natural_int8_t_to_stereo,
+                conv_swap_int16_t_to_stereo
+            }
         }
     }
 };
 
-f_sample *mixeng_clip[2][2][2] = {
+f_sample *mixeng_clip[2][2][2][2] = {
     {
         {
-            clip_uint8_t_from_mono,
-            clip_uint16_t_from_mono
+            {
+                clip_natural_uint8_t_from_mono,
+                clip_natural_uint16_t_from_mono
+            },
+            {
+                clip_natural_uint8_t_from_mono,
+                clip_swap_uint16_t_from_mono
+            }
         },
         {
-            clip_int8_t_from_mono,
-            clip_int16_t_from_mono
+            {
+                clip_natural_int8_t_from_mono,
+                clip_natural_int16_t_from_mono
+            },
+            {
+                clip_natural_int8_t_from_mono,
+                clip_swap_int16_t_from_mono
+            }
         }
     },
     {
         {
-            clip_uint8_t_from_stereo,
-            clip_uint16_t_from_stereo
+            {
+                clip_natural_uint8_t_from_stereo,
+                clip_natural_uint16_t_from_stereo
+            },
+            {
+                clip_natural_uint8_t_from_stereo,
+                clip_swap_uint16_t_from_stereo
+            }
         },
         {
-            clip_int8_t_from_stereo,
-            clip_int16_t_from_stereo
+            {
+                clip_natural_int8_t_from_stereo,
+                clip_natural_int16_t_from_stereo
+            },
+            {
+                clip_natural_int8_t_from_stereo,
+                clip_swap_int16_t_from_stereo
+            }
         }
     }
 };
@@ -116,9 +203,9 @@ f_sample *mixeng_clip[2][2][2] = {
  * Contributors with a more efficient algorithm.]
  *
  * This source code is freely redistributable and may be used for
- * any purpose.  This copyright notice must be maintained. 
- * Lance Norskog And Sundry Contributors are not responsible for 
- * the consequences of using this software.  
+ * any purpose.  This copyright notice must be maintained.
+ * Lance Norskog And Sundry Contributors are not responsible for
+ * the consequences of using this software.
  */
 
 /*
@@ -141,36 +228,29 @@ f_sample *mixeng_clip[2][2][2] = {
  */
 
 /* Private data */
-typedef struct ratestuff {
+struct rate {
     uint64_t opos;
     uint64_t opos_inc;
     uint32_t ipos;              /* position in the input stream (integer) */
     st_sample_t ilast;          /* last sample in the input stream */
-} *rate_t;
+};
 
 /*
  * Prepare processing.
  */
 void *st_rate_start (int inrate, int outrate)
 {
-    rate_t rate = (rate_t) qemu_mallocz (sizeof (struct ratestuff));
+    struct rate *rate = audio_calloc (AUDIO_FUNC, 1, sizeof (*rate));
 
     if (!rate) {
-        exit (EXIT_FAILURE);
-    }
-
-    if (inrate == outrate) {
-        // exit (EXIT_FAILURE);
-    }
-
-    if (inrate >= 65535 || outrate >= 65535) {
-        // exit (EXIT_FAILURE);
+        dolog ("Could not allocate resampler (%zu bytes)\n", sizeof (*rate));
+        return NULL;
     }
 
     rate->opos = 0;
 
     /* increment */
-    rate->opos_inc = (inrate * ((int64_t) UINT_MAX)) / outrate;
+    rate->opos_inc = ((uint64_t) inrate << 32) / outrate;
 
     rate->ipos = 0;
     rate->ilast.l = 0;
@@ -178,78 +258,20 @@ void *st_rate_start (int inrate, int outrate)
     return rate;
 }
 
-/*
- * Processed signed long samples from ibuf to obuf.
- * Return number of samples processed.
- */
-void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
-                   int *isamp, int *osamp)
-{
-    rate_t rate = (rate_t) opaque;
-    st_sample_t *istart, *iend;
-    st_sample_t *ostart, *oend;
-    st_sample_t ilast, icur, out;
-    int64_t t;
-
-    ilast = rate->ilast;
-
-    istart = ibuf;
-    iend = ibuf + *isamp;
+#define NAME st_rate_flow_mix
+#define OP(a, b) a += b
+#include "rate_template.h"
 
-    ostart = obuf;
-    oend = obuf + *osamp;
-
-    if (rate->opos_inc == 1ULL << 32) {
-        int i, n = *isamp > *osamp ? *osamp : *isamp;
-        for (i = 0; i < n; i++) {
-            obuf[i].l += ibuf[i].r;
-            obuf[i].r += ibuf[i].r;
-        }
-        *isamp = n;
-        *osamp = n;
-        return;
-    }
-
-    while (obuf < oend) {
-
-        /* Safety catch to make sure we have input samples.  */
-        if (ibuf >= iend)
-            break;
-
-        /* read as many input samples so that ipos > opos */
-
-        while (rate->ipos <= (rate->opos >> 32)) {
-            ilast = *ibuf++;
-            rate->ipos++;
-            /* See if we finished the input buffer yet */
-            if (ibuf >= iend) goto the_end;
-        }
-
-        icur = *ibuf;
-
-        /* interpolate */
-        t = rate->opos & 0xffffffff;
-        out.l = (ilast.l * (INT_MAX - t) + icur.l * t) / INT_MAX;
-        out.r = (ilast.r * (INT_MAX - t) + icur.r * t) / INT_MAX;
-
-        /* output sample & increment position */
-#if 0
-        *obuf++ = out;
-#else
-        obuf->l += out.l;
-        obuf->r += out.r;
-        obuf += 1;
-#endif
-        rate->opos += rate->opos_inc;
-    }
-
-the_end:
-    *isamp = ibuf - istart;
-    *osamp = obuf - ostart;
-    rate->ilast = ilast;
-}
+#define NAME st_rate_flow
+#define OP(a, b) a = b
+#include "rate_template.h"
 
 void st_rate_stop (void *opaque)
 {
     qemu_free (opaque);
 }
+
+void mixeng_clear (st_sample_t *buf, int len)
+{
+    memset (buf, 0, len * sizeof (st_sample_t));
+}
index 699435e..9e3bac1 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * QEMU Mixing engine header
- * 
- * Copyright (c) 2004 Vassili Karpov (malc)
- * 
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
  * 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
 #ifndef QEMU_MIXENG_H
 #define QEMU_MIXENG_H
 
-typedef void (t_sample) (void *dst, const void *src, int samples);
-typedef void (f_sample) (void *dst, const void *src, int samples);
+#ifdef FLOAT_MIXENG
+typedef float real_t;
+typedef struct { int mute; real_t r; real_t l; } volume_t;
+typedef struct { real_t l; real_t r; } st_sample_t;
+#else
+typedef struct { int mute; int64_t r; int64_t l; } volume_t;
 typedef struct { int64_t l; int64_t r; } st_sample_t;
+#endif
+
+typedef void (t_sample) (st_sample_t *dst, const void *src,
+                         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];
-extern f_sample *mixeng_clip[2][2][2];
+extern t_sample *mixeng_conv[2][2][2][2];
+extern f_sample *mixeng_clip[2][2][2][2];
 
 void *st_rate_start (int inrate, int outrate);
 void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
                    int *isamp, int *osamp);
+void st_rate_flow_mix (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
+                       int *isamp, int *osamp);
 void st_rate_stop (void *opaque);
+void mixeng_clear (st_sample_t *buf, int len);
 
 #endif  /* mixeng.h */
index f3b3f65..d726441 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * QEMU Mixing engine
- * 
- * Copyright (c) 2004 Vassili Karpov (malc)
- * 
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
  * 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
  * dec++'ified by Dscho
  */
 
+#ifndef SIGNED
+#define HALF (IN_MAX >> 1)
+#endif
+
+#ifdef NOVOL
+#define VOL(a, b) a
+#else
+#ifdef FLOAT_MIXENG
+#define VOL(a, b) ((a) * (b))
+#else
+#define VOL(a, b) ((a) * (b)) >> 32
+#endif
+#endif
+
+#define ET glue (ENDIAN_CONVERSION, glue (_, IN_T))
+
+#ifdef FLOAT_MIXENG
+static real_t inline glue (conv_, ET) (IN_T v)
+{
+    IN_T nv = ENDIAN_CONVERT (v);
+
+#ifdef RECIPROCAL
+#ifdef SIGNED
+    return nv * (1.f / (real_t) (IN_MAX - IN_MIN));
+#else
+    return (nv - HALF) * (1.f / (real_t) IN_MAX);
+#endif
+#else  /* !RECIPROCAL */
 #ifdef SIGNED
-#define HALFT IN_MAX
-#define HALF IN_MAX
+    return nv / (real_t) (IN_MAX - IN_MIN);
 #else
-#define HALFT ((IN_MAX)>>1)
-#define HALF HALFT
+    return (nv - HALF) / (real_t) IN_MAX;
 #endif
+#endif
+}
 
-static int64_t inline glue(conv_,IN_T) (IN_T v)
+static IN_T inline glue (clip_, ET) (real_t v)
 {
+    if (v >= 0.5) {
+        return IN_MAX;
+    }
+    else if (v < -0.5) {
+        return IN_MIN;
+    }
+
+#ifdef SIGNED
+    return ENDIAN_CONVERT ((IN_T) (v * (IN_MAX - IN_MIN)));
+#else
+    return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF));
+#endif
+}
+
+#else  /* !FLOAT_MIXENG */
+
+static inline int64_t glue (conv_, ET) (IN_T v)
+{
+    IN_T nv = ENDIAN_CONVERT (v);
 #ifdef SIGNED
-    return (INT_MAX*(int64_t)v)/HALF;
+    return ((int64_t) nv) << (32 - SHIFT);
 #else
-    return (INT_MAX*((int64_t)v-HALFT))/HALF;
+    return ((int64_t) nv - HALF) << (32 - SHIFT);
 #endif
 }
 
-static IN_T inline glue(clip_,IN_T) (int64_t v)
+static inline IN_T glue (clip_, ET) (int64_t v)
 {
-    if (v >= INT_MAX)
+    if (v >= 0x7f000000) {
         return IN_MAX;
-    else if (v < -INT_MAX)
+    }
+    else if (v < -2147483648LL) {
         return IN_MIN;
+    }
 
 #ifdef SIGNED
-    return (IN_T) (v*HALF/INT_MAX);
+    return ENDIAN_CONVERT ((IN_T) (v >> (32 - SHIFT)));
 #else
-    return (IN_T) (v+INT_MAX/2)*HALF/INT_MAX;
+    return ENDIAN_CONVERT ((IN_T) ((v >> (32 - SHIFT)) + HALF));
 #endif
 }
+#endif
 
-static void glue(glue(conv_,IN_T),_to_stereo) (void *dst, const void *src,
-                                               int samples)
+static void glue (glue (conv_, ET), _to_stereo)
+    (st_sample_t *dst, const void *src, int samples, volume_t *vol)
 {
-    st_sample_t *out = (st_sample_t *) dst;
+    st_sample_t *out = dst;
     IN_T *in = (IN_T *) src;
+#ifndef NOVOL
+    if (vol->mute) {
+        mixeng_clear (dst, samples);
+        return;
+    }
+#else
+    (void) vol;
+#endif
     while (samples--) {
-        out->l = glue(conv_,IN_T) (*in++);
-        out->r = glue(conv_,IN_T) (*in++);
+        out->l = VOL (glue (conv_, ET) (*in++), vol->l);
+        out->r = VOL (glue (conv_, ET) (*in++), vol->r);
         out += 1;
     }
 }
 
-static void glue(glue(conv_,IN_T),_to_mono) (void *dst, const void *src,
-                                             int samples)
+static void glue (glue (conv_, ET), _to_mono)
+    (st_sample_t *dst, const void *src, int samples, volume_t *vol)
 {
-    st_sample_t *out = (st_sample_t *) dst;
+    st_sample_t *out = dst;
     IN_T *in = (IN_T *) src;
+#ifndef NOVOL
+    if (vol->mute) {
+        mixeng_clear (dst, samples);
+        return;
+    }
+#else
+    (void) vol;
+#endif
     while (samples--) {
-        out->l = glue(conv_,IN_T) (in[0]);
+        out->l = VOL (glue (conv_, ET) (in[0]), vol->l);
         out->r = out->l;
         out += 1;
         in += 1;
     }
 }
 
-static void glue(glue(clip_,IN_T),_from_stereo) (void *dst, const void *src,
-                                                 int samples)
+static void glue (glue (clip_, ET), _from_stereo)
+    (void *dst, const st_sample_t *src, int samples)
 {
-    st_sample_t *in = (st_sample_t *) src;
+    const st_sample_t *in = src;
     IN_T *out = (IN_T *) dst;
     while (samples--) {
-        *out++ = glue(clip_,IN_T) (in->l);
-        *out++ = glue(clip_,IN_T) (in->r);
+        *out++ = glue (clip_, ET) (in->l);
+        *out++ = glue (clip_, ET) (in->r);
         in += 1;
     }
 }
 
-static void glue(glue(clip_,IN_T),_from_mono) (void *dst, const void *src,
-                                               int samples)
+static void glue (glue (clip_, ET), _from_mono)
+    (void *dst, const st_sample_t *src, int samples)
 {
-    st_sample_t *in = (st_sample_t *) src;
+    const st_sample_t *in = src;
     IN_T *out = (IN_T *) dst;
     while (samples--) {
-        *out++ = glue(clip_,IN_T) (in->l + in->r);
+        *out++ = glue (clip_, ET) (in->l + in->r);
         in += 1;
     }
 }
 
+#undef ET
 #undef HALF
-#undef HALFT
-
+#undef VOL
index a192885..aa35811 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * QEMU NULL audio output driver
- * 
- * Copyright (c) 2004 Vassili Karpov (malc)
- * 
+ * QEMU Timer based audio emulation
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
  * 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
  */
 #include "vl.h"
 
-#include "audio/audio_int.h"
+#define AUDIO_CAP "noaudio"
+#include "audio_int.h"
 
-typedef struct NoVoice {
-    HWVoice hw;
+typedef struct NoVoiceOut {
+    HWVoiceOut hw;
     int64_t old_ticks;
-} NoVoice;
+} NoVoiceOut;
 
-#define dolog(...) AUD_log ("noaudio", __VA_ARGS__)
-#ifdef DEBUG
-#define ldebug(...) dolog (__VA_ARGS__)
-#else
-#define ldebug(...)
-#endif
+typedef struct NoVoiceIn {
+    HWVoiceIn hw;
+    int64_t old_ticks;
+} NoVoiceIn;
 
-static void no_hw_run (HWVoice *hw)
+static int no_run_out (HWVoiceOut *hw)
 {
-    NoVoice *no = (NoVoice *) hw;
-    int rpos, live, decr, samples;
-    st_sample_t *src;
+    NoVoiceOut *no = (NoVoiceOut *) hw;
+    int live, decr, samples;
     int64_t now = qemu_get_clock (vm_clock);
     int64_t ticks = now - no->old_ticks;
-    int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
+    int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
 
-    if (bytes > INT_MAX)
-        samples = INT_MAX >> hw->shift;
-    else
-        samples = bytes >> hw->shift;
+    if (bytes > INT_MAX) {
+        samples = INT_MAX >> hw->info.shift;
+    }
+    else {
+        samples = bytes >> hw->info.shift;
+    }
 
-    live = pcm_hw_get_live (hw);
-    if (live <= 0)
-        return;
+    live = audio_pcm_hw_get_live_out (&no->hw);
+    if (!live) {
+        return 0;
+    }
 
     no->old_ticks = now;
     decr = audio_MIN (live, samples);
-    samples = decr;
-    rpos = hw->rpos;
-    while (samples) {
-        int left_till_end_samples = hw->samples - rpos;
-        int convert_samples = audio_MIN (samples, left_till_end_samples);
+    hw->rpos = (hw->rpos + decr) % hw->samples;
+    return decr;
+}
 
-        src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
-        memset (src, 0, convert_samples * sizeof (st_sample_t));
+static int no_write (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
 
-        rpos = (rpos + convert_samples) % hw->samples;
-        samples -= convert_samples;
-    }
+static int no_init_out (HWVoiceOut *hw, audsettings_t *as)
+{
+    audio_pcm_init_info (&hw->info, as, 0);
+    hw->samples = 1024;
+    return 0;
+}
 
-    pcm_hw_dec_live (hw, decr);
-    hw->rpos = rpos;
+static void no_fini_out (HWVoiceOut *hw)
+{
+    (void) hw;
 }
 
-static int no_hw_write (SWVoice *sw, void *buf, int len)
+static int no_ctl_out (HWVoiceOut *hw, int cmd, ...)
 {
-    return pcm_hw_write (sw, buf, len);
+    (void) hw;
+    (void) cmd;
+    return 0;
 }
 
-static int no_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
+static int no_init_in (HWVoiceIn *hw, audsettings_t *as)
 {
-    hw->freq = freq;
-    hw->nchannels = nchannels;
-    hw->fmt = fmt;
-    hw->bufsize = 4096;
+    audio_pcm_init_info (&hw->info, as, 0);
+    hw->samples = 1024;
     return 0;
 }
 
-static void no_hw_fini (HWVoice *hw)
+static void no_fini_in (HWVoiceIn *hw)
 {
     (void) hw;
 }
 
-static int no_hw_ctl (HWVoice *hw, int cmd, ...)
+static int no_run_in (HWVoiceIn *hw)
+{
+    NoVoiceIn *no = (NoVoiceIn *) hw;
+    int64_t now = qemu_get_clock (vm_clock);
+    int64_t ticks = now - no->old_ticks;
+    int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
+    int live = audio_pcm_hw_get_live_in (hw);
+    int dead = hw->samples - live;
+    int samples;
+
+    bytes = audio_MIN (bytes, INT_MAX);
+    samples = bytes >> hw->info.shift;
+    samples = audio_MIN (samples, dead);
+
+    return samples;
+}
+
+static int no_read (SWVoiceIn *sw, void *buf, int size)
+{
+    int samples = size >> sw->info.shift;
+    int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
+    int to_clear = audio_MIN (samples, total);
+    audio_pcm_info_clear_buf (&sw->info, buf, to_clear);
+    return to_clear;
+}
+
+static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)
 {
     (void) hw;
     (void) cmd;
@@ -107,22 +138,33 @@ static void *no_audio_init (void)
 
 static void no_audio_fini (void *opaque)
 {
+    (void) opaque;
 }
 
-struct pcm_ops no_pcm_ops = {
-    no_hw_init,
-    no_hw_fini,
-    no_hw_run,
-    no_hw_write,
-    no_hw_ctl
+static struct audio_pcm_ops no_pcm_ops = {
+    no_init_out,
+    no_fini_out,
+    no_run_out,
+    no_write,
+    no_ctl_out,
+
+    no_init_in,
+    no_fini_in,
+    no_run_in,
+    no_read,
+    no_ctl_in
 };
 
-struct audio_output_driver no_output_driver = {
-    "none",
-    no_audio_init,
-    no_audio_fini,
-    &no_pcm_ops,
-    1,
-    1,
-    sizeof (NoVoice)
+struct audio_driver no_audio_driver = {
+    INIT_FIELD (name           = ) "none",
+    INIT_FIELD (descr          = ) "Timer based audio emulation",
+    INIT_FIELD (options        = ) NULL,
+    INIT_FIELD (init           = ) no_audio_init,
+    INIT_FIELD (fini           = ) no_audio_fini,
+    INIT_FIELD (pcm_ops        = ) &no_pcm_ops,
+    INIT_FIELD (can_be_default = ) 1,
+    INIT_FIELD (max_voices_out = ) INT_MAX,
+    INIT_FIELD (max_voices_in  = ) INT_MAX,
+    INIT_FIELD (voice_size_out = ) sizeof (NoVoiceOut),
+    INIT_FIELD (voice_size_in  = ) sizeof (NoVoiceIn)
 };
index 5246ebb..7d12f9e 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * QEMU OSS audio output driver
- * 
- * Copyright (c) 2003-2004 Vassili Karpov (malc)
- * 
+ * QEMU OSS audio driver
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
  * 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
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/soundcard.h>
-#include <assert.h>
 #include "vl.h"
 
-#include "audio/audio_int.h"
+#define AUDIO_CAP "oss"
+#include "audio_int.h"
 
-typedef struct OSSVoice {
-    HWVoice hw;
+typedef struct OSSVoiceOut {
+    HWVoiceOut hw;
     void *pcm_buf;
     int fd;
     int nfrags;
     int fragsize;
     int mmapped;
     int old_optr;
-} OSSVoice;
-
-#define dolog(...) AUD_log ("oss", __VA_ARGS__)
-#ifdef DEBUG
-#define ldebug(...) dolog (__VA_ARGS__)
-#else
-#define ldebug(...)
-#endif
+} OSSVoiceOut;
 
-#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE"
-#define QC_OSS_NFRAGS   "QEMU_OSS_NFRAGS"
-#define QC_OSS_MMAP     "QEMU_OSS_MMAP"
-#define QC_OSS_DEV      "QEMU_OSS_DEV"
-
-#define errstr() strerror (errno)
+typedef struct OSSVoiceIn {
+    HWVoiceIn hw;
+    void *pcm_buf;
+    int fd;
+    int nfrags;
+    int fragsize;
+    int old_optr;
+} OSSVoiceIn;
 
 static struct {
     int try_mmap;
     int nfrags;
     int fragsize;
-    const char *dspname;
+    const char *devpath_out;
+    const char *devpath_in;
 } conf = {
     .try_mmap = 0,
     .nfrags = 4,
     .fragsize = 4096,
-    .dspname = "/dev/dsp"
+    .devpath_out = "/dev/dsp",
+    .devpath_in = "/dev/dsp"
 };
 
 struct oss_params {
@@ -74,65 +71,141 @@ struct oss_params {
     int fragsize;
 };
 
-static int oss_hw_write (SWVoice *sw, void *buf, int len)
+static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
+}
+
+static void GCC_FMT_ATTR (3, 4) oss_logerr2 (
+    int err,
+    const char *typ,
+    const char *fmt,
+    ...
+    )
+{
+    va_list ap;
+
+    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
+}
+
+static void oss_anal_close (int *fdp)
+{
+    int err = close (*fdp);
+    if (err) {
+        oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
+    }
+    *fdp = -1;
+}
+
+static int oss_write (SWVoiceOut *sw, void *buf, int len)
 {
-    return pcm_hw_write (sw, buf, len);
+    return audio_pcm_sw_write (sw, buf, len);
 }
 
-static int AUD_to_ossfmt (audfmt_e fmt)
+static int aud_to_ossfmt (audfmt_e fmt)
 {
     switch (fmt) {
-    case AUD_FMT_S8: return AFMT_S8;
-    case AUD_FMT_U8: return AFMT_U8;
-    case AUD_FMT_S16: return AFMT_S16_LE;
-    case AUD_FMT_U16: return AFMT_U16_LE;
+    case AUD_FMT_S8:
+        return AFMT_S8;
+
+    case AUD_FMT_U8:
+        return AFMT_U8;
+
+    case AUD_FMT_S16:
+        return AFMT_S16_LE;
+
+    case AUD_FMT_U16:
+        return AFMT_U16_LE;
+
     default:
-        dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
-        exit (EXIT_FAILURE);
+        dolog ("Internal logic error: Bad audio format %d\n", fmt);
+#ifdef DEBUG_AUDIO
+        abort ();
+#endif
+        return AFMT_U8;
     }
 }
 
-static int oss_to_audfmt (int fmt)
+static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness)
 {
-    switch (fmt) {
-    case AFMT_S8: return AUD_FMT_S8;
-    case AFMT_U8: return AUD_FMT_U8;
-    case AFMT_S16_LE: return AUD_FMT_S16;
-    case AFMT_U16_LE: return AUD_FMT_U16;
+    switch (ossfmt) {
+    case AFMT_S8:
+        *endianness =0;
+        *fmt = AUD_FMT_S8;
+        break;
+
+    case AFMT_U8:
+        *endianness = 0;
+        *fmt = AUD_FMT_U8;
+        break;
+
+    case AFMT_S16_LE:
+        *endianness = 0;
+        *fmt = AUD_FMT_S16;
+        break;
+
+    case AFMT_U16_LE:
+        *endianness = 0;
+        *fmt = AUD_FMT_U16;
+        break;
+
+    case AFMT_S16_BE:
+        *endianness = 1;
+        *fmt = AUD_FMT_S16;
+        break;
+
+    case AFMT_U16_BE:
+        *endianness = 1;
+        *fmt = AUD_FMT_U16;
+        break;
+
     default:
-        dolog ("Internal logic error: Unrecognized OSS audio format %d\n"
-               "Aborting\n",
-               fmt);
-        exit (EXIT_FAILURE);
+        dolog ("Unrecognized audio format %d\n", ossfmt);
+        return -1;
     }
+
+    return 0;
 }
 
-#ifdef DEBUG_PCM
-static void oss_dump_pcm_info (struct oss_params *req, struct oss_params *obt)
+#if defined DEBUG_MISMATCHES || defined DEBUG
+static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
 {
     dolog ("parameter | requested value | obtained value\n");
     dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
-    dolog ("channels  |      %10d |     %10d\n", req->nchannels, obt->nchannels);
+    dolog ("channels  |      %10d |     %10d\n",
+           req->nchannels, obt->nchannels);
     dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
     dolog ("nfrags    |      %10d |     %10d\n", req->nfrags, obt->nfrags);
-    dolog ("fragsize  |      %10d |     %10d\n", req->fragsize, obt->fragsize);
+    dolog ("fragsize  |      %10d |     %10d\n",
+           req->fragsize, obt->fragsize);
 }
 #endif
 
-static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd)
+static int oss_open (int in, struct oss_params *req,
+                     struct oss_params *obt, int *pfd)
 {
     int fd;
     int mmmmssss;
     audio_buf_info abinfo;
     int fmt, freq, nchannels;
-    const char *dspname = conf.dspname;
+    const char *dspname = in ? conf.devpath_in : conf.devpath_out;
+    const char *typ = in ? "ADC" : "DAC";
 
-    fd = open (dspname, O_WRONLY | O_NONBLOCK);
+    fd = open (dspname, (in ? O_RDONLY : O_WRONLY) | O_NONBLOCK);
     if (-1 == fd) {
-        dolog ("Could not initialize audio hardware. Failed to open `%s':\n"
-               "Reason:%s\n",
-               dspname,
-               errstr ());
+        oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
         return -1;
     }
 
@@ -141,52 +214,35 @@ static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd)
     fmt = req->fmt;
 
     if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
-        dolog ("Could not initialize audio hardware\n"
-               "Failed to set sample size\n"
-               "Reason: %s\n",
-               errstr ());
+        oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
         goto err;
     }
 
     if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
-        dolog ("Could not initialize audio hardware\n"
-               "Failed to set number of channels\n"
-               "Reason: %s\n",
-               errstr ());
+        oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
+                     req->nchannels);
         goto err;
     }
 
     if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
-        dolog ("Could not initialize audio hardware\n"
-               "Failed to set frequency\n"
-               "Reason: %s\n",
-               errstr ());
+        oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq);
         goto err;
     }
 
     if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) {
-        dolog ("Could not initialize audio hardware\n"
-               "Failed to set non-blocking mode\n"
-               "Reason: %s\n",
-               errstr ());
+        oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
         goto err;
     }
 
     mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize);
     if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
-        dolog ("Could not initialize audio hardware\n"
-               "Failed to set buffer length (%d, %d)\n"
-               "Reason:%s\n",
-               conf.nfrags, conf.fragsize,
-               errstr ());
+        oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
+                     req->nfrags, req->fragsize);
         goto err;
     }
 
-    if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &abinfo)) {
-        dolog ("Could not initialize audio hardware\n"
-               "Failed to get buffer length\n"
-               "Reason:%s\n",
-               errstr ());
+    if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
+        oss_logerr2 (errno, typ, "Failed to get buffer length\n");
         goto err;
     }
 
@@ -197,75 +253,87 @@ static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd)
     obt->fragsize = abinfo.fragsize;
     *pfd = fd;
 
+#ifdef DEBUG_MISMATCHES
     if ((req->fmt != obt->fmt) ||
         (req->nchannels != obt->nchannels) ||
         (req->freq != obt->freq) ||
         (req->fragsize != obt->fragsize) ||
         (req->nfrags != obt->nfrags)) {
-#ifdef DEBUG_PCM
         dolog ("Audio parameters mismatch\n");
-        oss_dump_pcm_info (req, obt);
-#endif
+        oss_dump_info (req, obt);
     }
+#endif
 
-#ifdef DEBUG_PCM
-    oss_dump_pcm_info (req, obt);
+#ifdef DEBUG
+    oss_dump_info (req, obt);
 #endif
     return 0;
 
-err:
-    close (fd);
+ err:
+    oss_anal_close (&fd);
     return -1;
 }
 
-static void oss_hw_run (HWVoice *hw)
+static int oss_run_out (HWVoiceOut *hw)
 {
-    OSSVoice *oss = (OSSVoice *) hw;
+    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
     int err, rpos, live, decr;
     int samples;
     uint8_t *dst;
     st_sample_t *src;
     struct audio_buf_info abinfo;
     struct count_info cntinfo;
+    int bufsize;
+
+    live = audio_pcm_hw_get_live_out (hw);
+    if (!live) {
+        return 0;
+    }
 
-    live = pcm_hw_get_live (hw);
-    if (live <= 0)
-        return;
+    bufsize = hw->samples << hw->info.shift;
 
     if (oss->mmapped) {
         int bytes;
 
         err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
         if (err < 0) {
-            dolog ("SNDCTL_DSP_GETOPTR failed\nReason: %s\n", errstr ());
-            return;
+            oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
+            return 0;
         }
 
         if (cntinfo.ptr == oss->old_optr) {
-            if (abs (hw->samples - live) < 64)
-                dolog ("overrun\n");
-            return;
+            if (abs (hw->samples - live) < 64) {
+                dolog ("warning: Overrun\n");
+            }
+            return 0;
         }
 
         if (cntinfo.ptr > oss->old_optr) {
             bytes = cntinfo.ptr - oss->old_optr;
         }
         else {
-            bytes = hw->bufsize + cntinfo.ptr - oss->old_optr;
+            bytes = bufsize + cntinfo.ptr - oss->old_optr;
         }
 
-        decr = audio_MIN (bytes >> hw->shift, live);
+        decr = audio_MIN (bytes >> hw->info.shift, live);
     }
     else {
         err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
         if (err < 0) {
-            dolog ("SNDCTL_DSP_GETOSPACE failed\nReason: %s\n", errstr ());
-            return;
+            oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n");
+            return 0;
+        }
+
+        if (abinfo.bytes < 0 || abinfo.bytes > bufsize) {
+            ldebug ("warning: Invalid available size, size=%d bufsize=%d\n",
+                    abinfo.bytes, bufsize);
+            return 0;
         }
 
-        decr = audio_MIN (abinfo.bytes >> hw->shift, live);
-        if (decr <= 0)
-            return;
+        decr = audio_MIN (abinfo.bytes >> hw->info.shift, live);
+        if (!decr) {
+            return 0;
+        }
     }
 
     samples = decr;
@@ -274,33 +342,41 @@ static void oss_hw_run (HWVoice *hw)
         int left_till_end_samples = hw->samples - rpos;
         int convert_samples = audio_MIN (samples, left_till_end_samples);
 
-        src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
-        dst = advance (oss->pcm_buf, rpos << hw->shift);
+        src = hw->mix_buf + rpos;
+        dst = advance (oss->pcm_buf, rpos << hw->info.shift);
 
         hw->clip (dst, src, convert_samples);
         if (!oss->mmapped) {
             int written;
 
-            written = write (oss->fd, dst, convert_samples << hw->shift);
+            written = write (oss->fd, dst, convert_samples << hw->info.shift);
             /* XXX: follow errno recommendations ? */
             if (written == -1) {
-                dolog ("Failed to write audio\nReason: %s\n", errstr ());
+                oss_logerr (
+                    errno,
+                    "Failed to write %d bytes of audio data from %p\n",
+                    convert_samples << hw->info.shift,
+                    dst
+                    );
                 continue;
             }
 
-            if (written != convert_samples << hw->shift) {
-                int wsamples = written >> hw->shift;
-                int wbytes = wsamples << hw->shift;
+            if (written != convert_samples << hw->info.shift) {
+                int wsamples = written >> hw->info.shift;
+                int wbytes = wsamples << hw->info.shift;
                 if (wbytes != written) {
-                    dolog ("Unaligned write %d, %d\n", wbytes, written);
+                    dolog ("warning: Misaligned write %d (requested %d), "
+                           "alignment %d\n",
+                           wbytes, written, hw->info.align + 1);
                 }
-                memset (src, 0, wbytes);
-                decr -= samples;
+                mixeng_clear (src, wsamples);
+                decr -= wsamples;
                 rpos = (rpos + wsamples) % hw->samples;
                 break;
             }
         }
-        memset (src, 0, convert_samples * sizeof (st_sample_t));
+
+        mixeng_clear (src, convert_samples);
 
         rpos = (rpos + convert_samples) % hw->samples;
         samples -= convert_samples;
@@ -309,28 +385,24 @@ static void oss_hw_run (HWVoice *hw)
         oss->old_optr = cntinfo.ptr;
     }
 
-    pcm_hw_dec_live (hw, decr);
     hw->rpos = rpos;
+    return decr;
 }
 
-static void oss_hw_fini (HWVoice *hw)
+static void oss_fini_out (HWVoiceOut *hw)
 {
     int err;
-    OSSVoice *oss = (OSSVoice *) hw;
+    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 
-    ldebug ("oss_hw_fini\n");
-    err = close (oss->fd);
-    if (err) {
-        dolog ("Failed to close OSS descriptor\nReason: %s\n", errstr ());
-    }
-    oss->fd = -1;
+    ldebug ("oss_fini\n");
+    oss_anal_close (&oss->fd);
 
     if (oss->pcm_buf) {
         if (oss->mmapped) {
-            err = munmap (oss->pcm_buf, hw->bufsize);
+            err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
             if (err) {
-                dolog ("Failed to unmap OSS buffer\nReason: %s\n",
-                       errstr ());
+                oss_logerr (errno, "Failed to unmap buffer %p, size %d\n",
+                            oss->pcm_buf, hw->samples << hw->info.shift);
             }
         }
         else {
@@ -340,48 +412,79 @@ static void oss_hw_fini (HWVoice *hw)
     }
 }
 
-static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
+static int oss_init_out (HWVoiceOut *hw, audsettings_t *as)
 {
-    OSSVoice *oss = (OSSVoice *) hw;
+    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
     struct oss_params req, obt;
+    int endianness;
+    int err;
+    int fd;
+    audfmt_e effective_fmt;
+    audsettings_t obt_as;
+
+    oss->fd = -1;
 
-    assert (!oss->fd);
-    req.fmt = AUD_to_ossfmt (fmt);
-    req.freq = freq;
-    req.nchannels = nchannels;
+    req.fmt = aud_to_ossfmt (as->fmt);
+    req.freq = as->freq;
+    req.nchannels = as->nchannels;
     req.fragsize = conf.fragsize;
     req.nfrags = conf.nfrags;
 
-    if (oss_open (&req, &obt, &oss->fd))
+    if (oss_open (0, &req, &obt, &fd)) {
         return -1;
+    }
 
-    hw->freq = obt.freq;
-    hw->fmt = oss_to_audfmt (obt.fmt);
-    hw->nchannels = obt.nchannels;
+    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
+    if (err) {
+        oss_anal_close (&fd);
+        return -1;
+    }
 
+    obt_as.freq = obt.freq;
+    obt_as.nchannels = obt.nchannels;
+    obt_as.fmt = effective_fmt;
+
+    audio_pcm_init_info (
+        &hw->info,
+        &obt_as,
+        audio_need_to_swap_endian (endianness)
+        );
     oss->nfrags = obt.nfrags;
     oss->fragsize = obt.fragsize;
-    hw->bufsize = obt.nfrags * obt.fragsize;
+
+    if (obt.nfrags * obt.fragsize & hw->info.align) {
+        dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
+               obt.nfrags * obt.fragsize, hw->info.align + 1);
+    }
+
+    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
 
     oss->mmapped = 0;
     if (conf.try_mmap) {
-        oss->pcm_buf = mmap (0, hw->bufsize, PROT_READ | PROT_WRITE,
-                             MAP_SHARED, oss->fd, 0);
+        oss->pcm_buf = mmap (
+            0,
+            hw->samples << hw->info.shift,
+            PROT_READ | PROT_WRITE,
+            MAP_SHARED,
+            fd,
+            0
+            );
         if (oss->pcm_buf == MAP_FAILED) {
-            dolog ("Failed to mmap OSS device\nReason: %s\n",
-                   errstr ());
+            oss_logerr (errno, "Failed to map %d bytes of DAC\n",
+                        hw->samples << hw->info.shift);
         } else {
             int err;
             int trig = 0;
-            if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
-                dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
-                       errstr ());
+            if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
+                oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
             }
             else {
                 trig = PCM_ENABLE_OUTPUT;
-                if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
-                    dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
-                           "Reason: %s\n", errstr ());
+                if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
+                    oss_logerr (
+                        errno,
+                        "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
+                        );
                 }
                 else {
                     oss->mmapped = 1;
@@ -389,43 +492,55 @@ static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
             }
 
             if (!oss->mmapped) {
-                err = munmap (oss->pcm_buf, hw->bufsize);
+                err = munmap (oss->pcm_buf, hw->samples << hw->info.shift);
                 if (err) {
-                    dolog ("Failed to unmap OSS device\nReason: %s\n",
-                           errstr ());
+                    oss_logerr (errno, "Failed to unmap buffer %p size %d\n",
+                                oss->pcm_buf, hw->samples << hw->info.shift);
                 }
             }
         }
     }
 
     if (!oss->mmapped) {
-        oss->pcm_buf = qemu_mallocz (hw->bufsize);
+        oss->pcm_buf = audio_calloc (
+            AUDIO_FUNC,
+            hw->samples,
+            1 << hw->info.shift
+            );
         if (!oss->pcm_buf) {
-            close (oss->fd);
-            oss->fd = -1;
+            dolog (
+                "Could not allocate DAC buffer (%d samples, each %d bytes)\n",
+                hw->samples,
+                1 << hw->info.shift
+                );
+            oss_anal_close (&fd);
             return -1;
         }
     }
 
+    oss->fd = fd;
     return 0;
 }
 
-static int oss_hw_ctl (HWVoice *hw, int cmd, ...)
+static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...)
 {
     int trig;
-    OSSVoice *oss = (OSSVoice *) hw;
+    OSSVoiceOut *oss = (OSSVoiceOut *) hw;
 
-    if (!oss->mmapped)
+    if (!oss->mmapped) {
         return 0;
+    }
 
     switch (cmd) {
     case VOICE_ENABLE:
         ldebug ("enabling voice\n");
-        pcm_hw_clear (hw, oss->pcm_buf, hw->samples);
+        audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples);
         trig = PCM_ENABLE_OUTPUT;
         if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
-            dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
-                   "Reason: %s\n", errstr ());
+            oss_logerr (
+                errno,
+                "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
+                );
             return -1;
         }
         break;
@@ -434,8 +549,7 @@ static int oss_hw_ctl (HWVoice *hw, int cmd, ...)
         ldebug ("disabling voice\n");
         trig = 0;
         if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
-            dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
-                   errstr ());
+            oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
             return -1;
         }
         break;
@@ -443,33 +557,206 @@ static int oss_hw_ctl (HWVoice *hw, int cmd, ...)
     return 0;
 }
 
+static int oss_init_in (HWVoiceIn *hw, audsettings_t *as)
+{
+    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
+    struct oss_params req, obt;
+    int endianness;
+    int err;
+    int fd;
+    audfmt_e effective_fmt;
+    audsettings_t obt_as;
+
+    oss->fd = -1;
+
+    req.fmt = aud_to_ossfmt (as->fmt);
+    req.freq = as->freq;
+    req.nchannels = as->nchannels;
+    req.fragsize = conf.fragsize;
+    req.nfrags = conf.nfrags;
+    if (oss_open (1, &req, &obt, &fd)) {
+        return -1;
+    }
+
+    err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
+    if (err) {
+        oss_anal_close (&fd);
+        return -1;
+    }
+
+    obt_as.freq = obt.freq;
+    obt_as.nchannels = obt.nchannels;
+    obt_as.fmt = effective_fmt;
+
+    audio_pcm_init_info (
+        &hw->info,
+        &obt_as,
+        audio_need_to_swap_endian (endianness)
+        );
+    oss->nfrags = obt.nfrags;
+    oss->fragsize = obt.fragsize;
+
+    if (obt.nfrags * obt.fragsize & hw->info.align) {
+        dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
+               obt.nfrags * obt.fragsize, hw->info.align + 1);
+    }
+
+    hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift;
+    oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+    if (!oss->pcm_buf) {
+        dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
+               hw->samples, 1 << hw->info.shift);
+        oss_anal_close (&fd);
+        return -1;
+    }
+
+    oss->fd = fd;
+    return 0;
+}
+
+static void oss_fini_in (HWVoiceIn *hw)
+{
+    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
+
+    oss_anal_close (&oss->fd);
+
+    if (oss->pcm_buf) {
+        qemu_free (oss->pcm_buf);
+        oss->pcm_buf = NULL;
+    }
+}
+
+static int oss_run_in (HWVoiceIn *hw)
+{
+    OSSVoiceIn *oss = (OSSVoiceIn *) hw;
+    int hwshift = hw->info.shift;
+    int i;
+    int live = audio_pcm_hw_get_live_in (hw);
+    int dead = hw->samples - live;
+    size_t read_samples = 0;
+    struct {
+        int add;
+        int len;
+    } bufs[2] = {
+        { hw->wpos, 0 },
+        { 0, 0 }
+    };
+
+    if (!dead) {
+        return 0;
+    }
+
+    if (hw->wpos + dead > hw->samples) {
+        bufs[0].len = (hw->samples - hw->wpos) << hwshift;
+        bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift;
+    }
+    else {
+        bufs[0].len = dead << hwshift;
+    }
+
+
+    for (i = 0; i < 2; ++i) {
+        ssize_t nread;
+
+        if (bufs[i].len) {
+            void *p = advance (oss->pcm_buf, bufs[i].add << hwshift);
+            nread = read (oss->fd, p, bufs[i].len);
+
+            if (nread > 0) {
+                if (nread & hw->info.align) {
+                    dolog ("warning: Misaligned read %zd (requested %d), "
+                           "alignment %d\n", nread, bufs[i].add << hwshift,
+                           hw->info.align + 1);
+                }
+                read_samples += nread >> hwshift;
+                hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift,
+                          &nominal_volume);
+            }
+
+            if (bufs[i].len - nread) {
+                if (nread == -1) {
+                    switch (errno) {
+                    case EINTR:
+                    case EAGAIN:
+                        break;
+                    default:
+                        oss_logerr (
+                            errno,
+                            "Failed to read %d bytes of audio (to %p)\n",
+                            bufs[i].len, p
+                            );
+                        break;
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    hw->wpos = (hw->wpos + read_samples) % hw->samples;
+    return read_samples;
+}
+
+static int oss_read (SWVoiceIn *sw, void *buf, int size)
+{
+    return audio_pcm_sw_read (sw, buf, size);
+}
+
+static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+    (void) hw;
+    (void) cmd;
+    return 0;
+}
+
 static void *oss_audio_init (void)
 {
-    conf.fragsize = audio_get_conf_int (QC_OSS_FRAGSIZE, conf.fragsize);
-    conf.nfrags = audio_get_conf_int (QC_OSS_NFRAGS, conf.nfrags);
-    conf.try_mmap = audio_get_conf_int (QC_OSS_MMAP, conf.try_mmap);
-    conf.dspname = audio_get_conf_str (QC_OSS_DEV, conf.dspname);
     return &conf;
 }
 
 static void oss_audio_fini (void *opaque)
 {
+    (void) opaque;
 }
 
-struct pcm_ops oss_pcm_ops = {
-    oss_hw_init,
-    oss_hw_fini,
-    oss_hw_run,
-    oss_hw_write,
-    oss_hw_ctl
+static struct audio_option oss_options[] = {
+    {"FRAGSIZE", AUD_OPT_INT, &conf.fragsize,
+     "Fragment size in bytes", NULL, 0},
+    {"NFRAGS", AUD_OPT_INT, &conf.nfrags,
+     "Number of fragments", NULL, 0},
+    {"MMAP", AUD_OPT_BOOL, &conf.try_mmap,
+     "Try using memory mapped access", NULL, 0},
+    {"DAC_DEV", AUD_OPT_STR, &conf.devpath_out,
+     "Path to DAC device", NULL, 0},
+    {"ADC_DEV", AUD_OPT_STR, &conf.devpath_in,
+     "Path to ADC device", NULL, 0},
+    {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+static struct audio_pcm_ops oss_pcm_ops = {
+    oss_init_out,
+    oss_fini_out,
+    oss_run_out,
+    oss_write,
+    oss_ctl_out,
+
+    oss_init_in,
+    oss_fini_in,
+    oss_run_in,
+    oss_read,
+    oss_ctl_in
 };
 
-struct audio_output_driver oss_output_driver = {
-    "oss",
-    oss_audio_init,
-    oss_audio_fini,
-    &oss_pcm_ops,
-    1,
-    INT_MAX,
-    sizeof (OSSVoice)
+struct audio_driver oss_audio_driver = {
+    INIT_FIELD (name           = ) "oss",
+    INIT_FIELD (descr          = ) "OSS http://www.opensound.com",
+    INIT_FIELD (options        = ) oss_options,
+    INIT_FIELD (init           = ) oss_audio_init,
+    INIT_FIELD (fini           = ) oss_audio_fini,
+    INIT_FIELD (pcm_ops        = ) &oss_pcm_ops,
+    INIT_FIELD (can_be_default = ) 1,
+    INIT_FIELD (max_voices_out = ) INT_MAX,
+    INIT_FIELD (max_voices_in  = ) INT_MAX,
+    INIT_FIELD (voice_size_out = ) sizeof (OSSVoiceOut),
+    INIT_FIELD (voice_size_in  = ) sizeof (OSSVoiceIn)
 };
diff --git a/qemu/audio/rate_template.h b/qemu/audio/rate_template.h
new file mode 100644 (file)
index 0000000..3e0e77c
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * QEMU Mixing engine
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ * Copyright (c) 1998 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.
+ */
+
+/*
+ * Processed signed long samples from ibuf to obuf.
+ * Return number of samples processed.
+ */
+void NAME (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
+           int *isamp, int *osamp)
+{
+    struct rate *rate = opaque;
+    st_sample_t *istart, *iend;
+    st_sample_t *ostart, *oend;
+    st_sample_t ilast, icur, out;
+#ifdef FLOAT_MIXENG
+    real_t t;
+#else
+    int64_t t;
+#endif
+
+    ilast = rate->ilast;
+
+    istart = ibuf;
+    iend = ibuf + *isamp;
+
+    ostart = obuf;
+    oend = obuf + *osamp;
+
+    if (rate->opos_inc == (1ULL + UINT_MAX)) {
+        int i, n = *isamp > *osamp ? *osamp : *isamp;
+        for (i = 0; i < n; i++) {
+            OP (obuf[i].l, ibuf[i].r);
+            OP (obuf[i].r, ibuf[i].r);
+        }
+        *isamp = n;
+        *osamp = n;
+        return;
+    }
+
+    while (obuf < oend) {
+
+        /* Safety catch to make sure we have input samples.  */
+        if (ibuf >= iend) {
+            break;
+        }
+
+        /* read as many input samples so that ipos > opos */
+
+        while (rate->ipos <= (rate->opos >> 32)) {
+            ilast = *ibuf++;
+            rate->ipos++;
+            /* See if we finished the input buffer yet */
+            if (ibuf >= iend) {
+                goto the_end;
+            }
+        }
+
+        icur = *ibuf;
+
+        /* interpolate */
+#ifdef FLOAT_MIXENG
+#ifdef RECIPROCAL
+        t = (rate->opos & UINT_MAX) * (1.f / UINT_MAX);
+#else
+        t = (rate->opos & UINT_MAX) / (real_t) UINT_MAX;
+#endif
+        out.l = (ilast.l * (1.0 - t)) + icur.l * t;
+        out.r = (ilast.r * (1.0 - t)) + icur.r * t;
+#else
+        t = rate->opos & 0xffffffff;
+        out.l = (ilast.l * ((int64_t) UINT_MAX - t) + icur.l * t) >> 32;
+        out.r = (ilast.r * ((int64_t) UINT_MAX - t) + icur.r * t) >> 32;
+#endif
+
+        /* output sample & increment position */
+        OP (obuf->l, out.l);
+        OP (obuf->r, out.r);
+        obuf += 1;
+        rate->opos += rate->opos_inc;
+    }
+
+the_end:
+    *isamp = ibuf - istart;
+    *osamp = obuf - ostart;
+    rate->ilast = ilast;
+}
+
+#undef NAME
+#undef OP
index 978686a..713c784 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * QEMU SDL audio output driver
- * 
- * Copyright (c) 2004 Vassili Karpov (malc)
- * 
+ * QEMU SDL audio driver
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
  * 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
 #include <SDL_thread.h>
 #include "vl.h"
 
-#include "audio/audio_int.h"
-
-typedef struct SDLVoice {
-    HWVoice hw;
-} SDLVoice;
-
-#define dolog(...) AUD_log ("sdl", __VA_ARGS__)
-#ifdef DEBUG
-#define ldebug(...) dolog (__VA_ARGS__)
-#else
-#define ldebug(...)
-#endif
-
-#define QC_SDL_SAMPLES "QEMU_SDL_SAMPLES"
+#define AUDIO_CAP "sdl"
+#include "audio_int.h"
 
-#define errstr() SDL_GetError ()
+typedef struct SDLVoiceOut {
+    HWVoiceOut hw;
+    int live;
+    int rpos;
+    int decr;
+} SDLVoiceOut;
 
 static struct {
     int nb_samples;
@@ -56,91 +49,129 @@ struct SDLAudioState {
 } glob_sdl;
 typedef struct SDLAudioState SDLAudioState;
 
-static void sdl_hw_run (HWVoice *hw)
+static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
 {
-    (void) hw;
+    va_list ap;
+
+    va_start (ap, fmt);
+    AUD_vlog (AUDIO_CAP, fmt, ap);
+    va_end (ap);
+
+    AUD_log (AUDIO_CAP, "Reason: %s\n", SDL_GetError ());
 }
 
-static int sdl_lock (SDLAudioState *s)
+static int sdl_lock (SDLAudioState *s, const char *forfn)
 {
     if (SDL_LockMutex (s->mutex)) {
-        dolog ("SDL_LockMutex failed\nReason: %s\n", errstr ());
+        sdl_logerr ("SDL_LockMutex for %s failed\n", forfn);
         return -1;
     }
     return 0;
 }
 
-static int sdl_unlock (SDLAudioState *s)
+static int sdl_unlock (SDLAudioState *s, const char *forfn)
 {
     if (SDL_UnlockMutex (s->mutex)) {
-        dolog ("SDL_UnlockMutex failed\nReason: %s\n", errstr ());
+        sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn);
         return -1;
     }
     return 0;
 }
 
-static int sdl_post (SDLAudioState *s)
+static int sdl_post (SDLAudioState *s, const char *forfn)
 {
     if (SDL_SemPost (s->sem)) {
-        dolog ("SDL_SemPost failed\nReason: %s\n", errstr ());
+        sdl_logerr ("SDL_SemPost for %s failed\n", forfn);
         return -1;
     }
     return 0;
 }
 
-static int sdl_wait (SDLAudioState *s)
+static int sdl_wait (SDLAudioState *s, const char *forfn)
 {
     if (SDL_SemWait (s->sem)) {
-        dolog ("SDL_SemWait failed\nReason: %s\n", errstr ());
+        sdl_logerr ("SDL_SemWait for %s failed\n", forfn);
         return -1;
     }
     return 0;
 }
 
-static int sdl_unlock_and_post (SDLAudioState *s)
+static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
 {
-    if (sdl_unlock (s))
+    if (sdl_unlock (s, forfn)) {
         return -1;
+    }
 
-    return sdl_post (s);
-}
-
-static int sdl_hw_write (SWVoice *sw, void *buf, int len)
-{
-    int ret;
-    SDLAudioState *s = &glob_sdl;
-    sdl_lock (s);
-    ret = pcm_hw_write (sw, buf, len);
-    sdl_unlock_and_post (s);
-    return ret;
+    return sdl_post (s, forfn);
 }
 
-static int AUD_to_sdlfmt (audfmt_e fmt, int *shift)
+static int aud_to_sdlfmt (audfmt_e fmt, int *shift)
 {
-    *shift = 0;
     switch (fmt) {
-    case AUD_FMT_S8: return AUDIO_S8;
-    case AUD_FMT_U8: return AUDIO_U8;
-    case AUD_FMT_S16: *shift = 1; return AUDIO_S16LSB;
-    case AUD_FMT_U16: *shift = 1; return AUDIO_U16LSB;
+    case AUD_FMT_S8:
+        *shift = 0;
+        return AUDIO_S8;
+
+    case AUD_FMT_U8:
+        *shift = 0;
+        return AUDIO_U8;
+
+    case AUD_FMT_S16:
+        *shift = 1;
+        return AUDIO_S16LSB;
+
+    case AUD_FMT_U16:
+        *shift = 1;
+        return AUDIO_U16LSB;
+
     default:
-        dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
-        exit (EXIT_FAILURE);
+        dolog ("Internal logic error: Bad audio format %d\n", fmt);
+#ifdef DEBUG_AUDIO
+        abort ();
+#endif
+        return AUDIO_U8;
     }
 }
 
-static int sdl_to_audfmt (int fmt)
+static int sdl_to_audfmt (int sdlfmt, audfmt_e *fmt, int *endianess)
 {
-    switch (fmt) {
-    case AUDIO_S8: return AUD_FMT_S8;
-    case AUDIO_U8: return AUD_FMT_U8;
-    case AUDIO_S16LSB: return AUD_FMT_S16;
-    case AUDIO_U16LSB: return AUD_FMT_U16;
+    switch (sdlfmt) {
+    case AUDIO_S8:
+        *endianess = 0;
+        *fmt = AUD_FMT_S8;
+        break;
+
+    case AUDIO_U8:
+        *endianess = 0;
+        *fmt = AUD_FMT_U8;
+        break;
+
+    case AUDIO_S16LSB:
+        *endianess = 0;
+        *fmt = AUD_FMT_S16;
+        break;
+
+    case AUDIO_U16LSB:
+        *endianess = 0;
+        *fmt = AUD_FMT_U16;
+        break;
+
+    case AUDIO_S16MSB:
+        *endianess = 1;
+        *fmt = AUD_FMT_S16;
+        break;
+
+    case AUDIO_U16MSB:
+        *endianess = 1;
+        *fmt = AUD_FMT_U16;
+        break;
+
     default:
-        dolog ("Internal logic error: Unrecognized SDL audio format %d\n"
-               "Aborting\n", fmt);
-        exit (EXIT_FAILURE);
+        dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
+        return -1;
     }
+
+    return 0;
 }
 
 static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
@@ -149,7 +180,7 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
 
     status = SDL_OpenAudio (req, obt);
     if (status) {
-        dolog ("SDL_OpenAudio failed\nReason: %s\n", errstr ());
+        sdl_logerr ("SDL_OpenAudio failed\n");
     }
     return status;
 }
@@ -157,9 +188,9 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
 static void sdl_close (SDLAudioState *s)
 {
     if (s->initialized) {
-        sdl_lock (s);
+        sdl_lock (s, "sdl_close");
         s->exit = 1;
-        sdl_unlock_and_post (s);
+        sdl_unlock_and_post (s, "sdl_close");
         SDL_PauseAudio (1);
         SDL_CloseAudio ();
         s->initialized = 0;
@@ -168,31 +199,40 @@ static void sdl_close (SDLAudioState *s)
 
 static void sdl_callback (void *opaque, Uint8 *buf, int len)
 {
-    SDLVoice *sdl = opaque;
+    SDLVoiceOut *sdl = opaque;
     SDLAudioState *s = &glob_sdl;
-    HWVoice *hw = &sdl->hw;
-    int samples = len >> hw->shift;
+    HWVoiceOut *hw = &sdl->hw;
+    int samples = len >> hw->info.shift;
 
     if (s->exit) {
         return;
     }
 
     while (samples) {
-        int to_mix, live, decr;
+        int to_mix, decr;
 
         /* dolog ("in callback samples=%d\n", samples); */
-        sdl_wait (s);
+        sdl_wait (s, "sdl_callback");
         if (s->exit) {
             return;
         }
 
-        sdl_lock (s);
-        live = pcm_hw_get_live (hw);
-        if (live <= 0)
+        if (sdl_lock (s, "sdl_callback")) {
+            return;
+        }
+
+        if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) {
+            dolog ("sdl->live=%d hw->samples=%d\n",
+                   sdl->live, hw->samples);
+            return;
+        }
+
+        if (!sdl->live) {
             goto again;
+        }
 
         /* dolog ("in callback live=%d\n", live); */
-        to_mix = audio_MIN (samples, live);
+        to_mix = audio_MIN (samples, sdl->live);
         decr = to_mix;
         while (to_mix) {
             int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
@@ -200,58 +240,109 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
 
             /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
             hw->clip (buf, src, chunk);
-            memset (src, 0, chunk * sizeof (st_sample_t));
-            hw->rpos = (hw->rpos + chunk) % hw->samples;
+            mixeng_clear (src, chunk);
+            sdl->rpos = (sdl->rpos + chunk) % hw->samples;
             to_mix -= chunk;
-            buf += chunk << hw->shift;
+            buf += chunk << hw->info.shift;
         }
         samples -= decr;
-        pcm_hw_dec_live (hw, decr);
+        sdl->live -= decr;
+        sdl->decr += decr;
 
     again:
-        sdl_unlock (s);
+        if (sdl_unlock (s, "sdl_callback")) {
+            return;
+        }
     }
     /* dolog ("done len=%d\n", len); */
 }
 
-static void sdl_hw_fini (HWVoice *hw)
+static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
+{
+    return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int sdl_run_out (HWVoiceOut *hw)
 {
-    ldebug ("sdl_hw_fini %d fixed=%d\n",
-             glob_sdl.initialized, audio_state.fixed_format);
+    int decr, live;
+    SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
+    SDLAudioState *s = &glob_sdl;
+
+    if (sdl_lock (s, "sdl_callback")) {
+        return 0;
+    }
+
+    live = audio_pcm_hw_get_live_out (hw);
+
+    if (sdl->decr > live) {
+        ldebug ("sdl->decr %d live %d sdl->live %d\n",
+                sdl->decr,
+                live,
+                sdl->live);
+    }
+
+    decr = audio_MIN (sdl->decr, live);
+    sdl->decr -= decr;
+
+    sdl->live = live - decr;
+    hw->rpos = sdl->rpos;
+
+    if (sdl->live > 0) {
+        sdl_unlock_and_post (s, "sdl_callback");
+    }
+    else {
+        sdl_unlock (s, "sdl_callback");
+    }
+    return decr;
+}
+
+static void sdl_fini_out (HWVoiceOut *hw)
+{
+    (void) hw;
+
     sdl_close (&glob_sdl);
 }
 
-static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
+static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as)
 {
-    SDLVoice *sdl = (SDLVoice *) hw;
+    SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
     SDLAudioState *s = &glob_sdl;
     SDL_AudioSpec req, obt;
     int shift;
+    int endianess;
+    int err;
+    audfmt_e effective_fmt;
+    audsettings_t obt_as;
 
-    ldebug ("sdl_hw_init %d freq=%d fixed=%d\n",
-            s->initialized, freq, audio_state.fixed_format);
-
-    if (nchannels != 2) {
-        dolog ("Bogus channel count %d\n", nchannels);
-        return -1;
-    }
+    shift <<= as->nchannels == 2;
 
-    req.freq = freq;
-    req.format = AUD_to_sdlfmt (fmt, &shift);
-    req.channels = nchannels;
+    req.freq = as->freq;
+    req.format = aud_to_sdlfmt (as->fmt, &shift);
+    req.channels = as->nchannels;
     req.samples = conf.nb_samples;
-    shift <<= nchannels == 2;
-
     req.callback = sdl_callback;
     req.userdata = sdl;
 
-    if (sdl_open (&req, &obt))
+    if (sdl_open (&req, &obt)) {
         return -1;
+    }
 
-    hw->freq = obt.freq;
-    hw->fmt = sdl_to_audfmt (obt.format);
-    hw->nchannels = obt.channels;
-    hw->bufsize = obt.samples << shift;
+    err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess);
+    if (err) {
+        sdl_close (s);
+        return -1;
+    }
+
+    obt_as.freq = obt.freq;
+    obt_as.nchannels = obt.channels;
+    obt_as.fmt = effective_fmt;
+
+    audio_pcm_init_info (
+        &hw->info,
+        &obt_as,
+        audio_need_to_swap_endian (endianess)
+        );
+    hw->samples = obt.samples;
 
     s->initialized = 1;
     s->exit = 0;
@@ -259,7 +350,7 @@ static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
     return 0;
 }
 
-static int sdl_hw_ctl (HWVoice *hw, int cmd, ...)
+static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)
 {
     (void) hw;
 
@@ -278,24 +369,22 @@ static int sdl_hw_ctl (HWVoice *hw, int cmd, ...)
 static void *sdl_audio_init (void)
 {
     SDLAudioState *s = &glob_sdl;
-    conf.nb_samples = audio_get_conf_int (QC_SDL_SAMPLES, conf.nb_samples);
 
     if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
-        dolog ("SDL failed to initialize audio subsystem\nReason: %s\n",
-               errstr ());
+        sdl_logerr ("SDL failed to initialize audio subsystem\n");
         return NULL;
     }
 
     s->mutex = SDL_CreateMutex ();
     if (!s->mutex) {
-        dolog ("Failed to create SDL mutex\nReason: %s\n", errstr ());
+        sdl_logerr ("Failed to create SDL mutex\n");
         SDL_QuitSubSystem (SDL_INIT_AUDIO);
         return NULL;
     }
 
     s->sem = SDL_CreateSemaphore (0);
     if (!s->sem) {
-        dolog ("Failed to create SDL semaphore\nReason: %s\n", errstr ());
+        sdl_logerr ("Failed to create SDL semaphore\n");
         SDL_DestroyMutex (s->mutex);
         SDL_QuitSubSystem (SDL_INIT_AUDIO);
         return NULL;
@@ -313,20 +402,36 @@ static void sdl_audio_fini (void *opaque)
     SDL_QuitSubSystem (SDL_INIT_AUDIO);
 }
 
-struct pcm_ops sdl_pcm_ops = {
-    sdl_hw_init,
-    sdl_hw_fini,
-    sdl_hw_run,
-    sdl_hw_write,
-    sdl_hw_ctl
+static struct audio_option sdl_options[] = {
+    {"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
+     "Size of SDL buffer in samples", NULL, 0},
+    {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+static struct audio_pcm_ops sdl_pcm_ops = {
+    sdl_init_out,
+    sdl_fini_out,
+    sdl_run_out,
+    sdl_write_out,
+    sdl_ctl_out,
+
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL
 };
 
-struct audio_output_driver sdl_output_driver = {
-    "sdl",
-    sdl_audio_init,
-    sdl_audio_fini,
-    &sdl_pcm_ops,
-    1,
-    1,
-    sizeof (SDLVoice)
+struct audio_driver sdl_audio_driver = {
+    INIT_FIELD (name           = ) "sdl",
+    INIT_FIELD (descr          = ) "SDL http://www.libsdl.org",
+    INIT_FIELD (options        = ) sdl_options,
+    INIT_FIELD (init           = ) sdl_audio_init,
+    INIT_FIELD (fini           = ) sdl_audio_fini,
+    INIT_FIELD (pcm_ops        = ) &sdl_pcm_ops,
+    INIT_FIELD (can_be_default = ) 1,
+    INIT_FIELD (max_voices_out = ) 1,
+    INIT_FIELD (max_voices_in  = ) 0,
+    INIT_FIELD (voice_size_out = ) sizeof (SDLVoiceOut),
+    INIT_FIELD (voice_size_in  = ) 0
 };
diff --git a/qemu/audio/sys-queue.h b/qemu/audio/sys-queue.h
new file mode 100644 (file)
index 0000000..5b6e2a0
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *     @(#)queue.h     8.3 (Berkeley) 12/13/93
+ */
+
+#ifndef        _SYS_QUEUE_H
+#define        _SYS_QUEUE_H 1
+
+/*
+ * This file defines three types of data structures: lists, tail queues,
+ * and circular queues.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list after
+ * an existing element or at the head of the list. A list may only be
+ * traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A tail queue may only be traversed in the forward direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type)                                          \
+struct name {                                                          \
+       struct type *lh_first;  /* first element */                     \
+}
+
+#define LIST_ENTRY(type)                                               \
+struct {                                                               \
+       struct type *le_next;   /* next element */                      \
+       struct type **le_prev;  /* address of previous next element */  \
+}
+
+/*
+ * List functions.
+ */
+#define        LIST_INIT(head) {                                               \
+       (head)->lh_first = NULL;                                        \
+}
+
+#define LIST_INSERT_AFTER(listelm, elm, field) {                       \
+       if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)  \
+               (listelm)->field.le_next->field.le_prev =               \
+                   &(elm)->field.le_next;                              \
+       (listelm)->field.le_next = (elm);                               \
+       (elm)->field.le_prev = &(listelm)->field.le_next;               \
+}
+
+#define LIST_INSERT_HEAD(head, elm, field) {                           \
+       if (((elm)->field.le_next = (head)->lh_first) != NULL)          \
+               (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+       (head)->lh_first = (elm);                                       \
+       (elm)->field.le_prev = &(head)->lh_first;                       \
+}
+
+#define LIST_REMOVE(elm, field) {                                      \
+       if ((elm)->field.le_next != NULL)                               \
+               (elm)->field.le_next->field.le_prev =                   \
+                   (elm)->field.le_prev;                               \
+       *(elm)->field.le_prev = (elm)->field.le_next;                   \
+}
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type)                                         \
+struct name {                                                          \
+       struct type *tqh_first; /* first element */                     \
+       struct type **tqh_last; /* addr of last next element */         \
+}
+
+#define TAILQ_ENTRY(type)                                              \
+struct {                                                               \
+       struct type *tqe_next;  /* next element */                      \
+       struct type **tqe_prev; /* address of previous next element */  \
+}
+
+/*
+ * Tail queue functions.
+ */
+#define        TAILQ_INIT(head) {                                              \
+       (head)->tqh_first = NULL;                                       \
+       (head)->tqh_last = &(head)->tqh_first;                          \
+}
+
+#define TAILQ_INSERT_HEAD(head, elm, field) {                          \
+       if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)        \
+               (elm)->field.tqe_next->field.tqe_prev =                 \
+                   &(elm)->field.tqe_next;                             \
+       else                                                            \
+               (head)->tqh_last = &(elm)->field.tqe_next;              \
+       (head)->tqh_first = (elm);                                      \
+       (elm)->field.tqe_prev = &(head)->tqh_first;                     \
+}
+
+#define TAILQ_INSERT_TAIL(head, elm, field) {                          \
+       (elm)->field.tqe_next = NULL;                                   \
+       (elm)->field.tqe_prev = (head)->tqh_last;                       \
+       *(head)->tqh_last = (elm);                                      \
+       (head)->tqh_last = &(elm)->field.tqe_next;                      \
+}
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) {                        \
+       if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+               (elm)->field.tqe_next->field.tqe_prev =                 \
+                   &(elm)->field.tqe_next;                             \
+       else                                                            \
+               (head)->tqh_last = &(elm)->field.tqe_next;              \
+       (listelm)->field.tqe_next = (elm);                              \
+       (elm)->field.tqe_prev = &(listelm)->field.tqe_next;             \
+}
+
+#define TAILQ_REMOVE(head, elm, field) {                               \
+       if (((elm)->field.tqe_next) != NULL)                            \
+               (elm)->field.tqe_next->field.tqe_prev =                 \
+                   (elm)->field.tqe_prev;                              \
+       else                                                            \
+               (head)->tqh_last = (elm)->field.tqe_prev;               \
+       *(elm)->field.tqe_prev = (elm)->field.tqe_next;                 \
+}
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type)                                       \
+struct name {                                                          \
+       struct type *cqh_first;         /* first element */             \
+       struct type *cqh_last;          /* last element */              \
+}
+
+#define CIRCLEQ_ENTRY(type)                                            \
+struct {                                                               \
+       struct type *cqe_next;          /* next element */              \
+       struct type *cqe_prev;          /* previous element */          \
+}
+
+/*
+ * Circular queue functions.
+ */
+#define        CIRCLEQ_INIT(head) {                                            \
+       (head)->cqh_first = (void *)(head);                             \
+       (head)->cqh_last = (void *)(head);                              \
+}
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) {              \
+       (elm)->field.cqe_next = (listelm)->field.cqe_next;              \
+       (elm)->field.cqe_prev = (listelm);                              \
+       if ((listelm)->field.cqe_next == (void *)(head))                \
+               (head)->cqh_last = (elm);                               \
+       else                                                            \
+               (listelm)->field.cqe_next->field.cqe_prev = (elm);      \
+       (listelm)->field.cqe_next = (elm);                              \
+}
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) {             \
+       (elm)->field.cqe_next = (listelm);                              \
+       (elm)->field.cqe_prev = (listelm)->field.cqe_prev;              \
+       if ((listelm)->field.cqe_prev == (void *)(head))                \
+               (head)->cqh_first = (elm);                              \
+       else                                                            \
+               (listelm)->field.cqe_prev->field.cqe_next = (elm);      \
+       (listelm)->field.cqe_prev = (elm);                              \
+}
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) {                                \
+       (elm)->field.cqe_next = (head)->cqh_first;                      \
+       (elm)->field.cqe_prev = (void *)(head);                         \
+       if ((head)->cqh_last == (void *)(head))                         \
+               (head)->cqh_last = (elm);                               \
+       else                                                            \
+               (head)->cqh_first->field.cqe_prev = (elm);              \
+       (head)->cqh_first = (elm);                                      \
+}
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) {                                \
+       (elm)->field.cqe_next = (void *)(head);                         \
+       (elm)->field.cqe_prev = (head)->cqh_last;                       \
+       if ((head)->cqh_first == (void *)(head))                        \
+               (head)->cqh_first = (elm);                              \
+       else                                                            \
+               (head)->cqh_last->field.cqe_next = (elm);               \
+       (head)->cqh_last = (elm);                                       \
+}
+
+#define        CIRCLEQ_REMOVE(head, elm, field) {                              \
+       if ((elm)->field.cqe_next == (void *)(head))                    \
+               (head)->cqh_last = (elm)->field.cqe_prev;               \
+       else                                                            \
+               (elm)->field.cqe_next->field.cqe_prev =                 \
+                   (elm)->field.cqe_prev;                              \
+       if ((elm)->field.cqe_prev == (void *)(head))                    \
+               (head)->cqh_first = (elm)->field.cqe_next;              \
+       else                                                            \
+               (elm)->field.cqe_prev->field.cqe_next =                 \
+                   (elm)->field.cqe_next;                              \
+}
+#endif /* sys/queue.h */
index 5680161..18d2bb0 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * QEMU WAV audio output driver
- * 
- * Copyright (c) 2004 Vassili Karpov (malc)
- * 
+ * QEMU WAV audio driver
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
  * 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
  */
 #include "vl.h"
 
-#include "audio/audio_int.h"
+#define AUDIO_CAP "wav"
+#include "audio_int.h"
 
-typedef struct WAVVoice {
-    HWVoice hw;
+typedef struct WAVVoiceOut {
+    HWVoiceOut hw;
     QEMUFile *f;
     int64_t old_ticks;
     void *pcm_buf;
     int total_samples;
-} WAVVoice;
-
-#define dolog(...) AUD_log ("wav", __VA_ARGS__)
-#ifdef DEBUG
-#define ldebug(...) dolog (__VA_ARGS__)
-#else
-#define ldebug(...)
-#endif
+} WAVVoiceOut;
 
 static struct {
+    audsettings_t settings;
     const char *wav_path;
 } conf = {
-    .wav_path = "qemu.wav"
+    {
+        44100,
+        2,
+        AUD_FMT_S16
+    },
+    "qemu.wav"
 };
 
-static void wav_hw_run (HWVoice *hw)
+static int wav_run_out (HWVoiceOut *hw)
 {
-    WAVVoice *wav = (WAVVoice *) hw;
+    WAVVoiceOut *wav = (WAVVoiceOut *) hw;
     int rpos, live, decr, samples;
     uint8_t *dst;
     st_sample_t *src;
     int64_t now = qemu_get_clock (vm_clock);
     int64_t ticks = now - wav->old_ticks;
-    int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
+    int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
 
-    if (bytes > INT_MAX)
-        samples = INT_MAX >> hw->shift;
-    else
-        samples = bytes >> hw->shift;
+    if (bytes > INT_MAX) {
+        samples = INT_MAX >> hw->info.shift;
+    }
+    else {
+        samples = bytes >> hw->info.shift;
+    }
 
-    live = pcm_hw_get_live (hw);
-    if (live <= 0)
-        return;
+    live = audio_pcm_hw_get_live_out (hw);
+    if (!live) {
+        return 0;
+    }
 
     wav->old_ticks = now;
     decr = audio_MIN (live, samples);
@@ -73,25 +76,25 @@ static void wav_hw_run (HWVoice *hw)
         int left_till_end_samples = hw->samples - rpos;
         int convert_samples = audio_MIN (samples, left_till_end_samples);
 
-        src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
-        dst = advance (wav->pcm_buf, rpos << hw->shift);
+        src = hw->mix_buf + rpos;
+        dst = advance (wav->pcm_buf, rpos << hw->info.shift);
 
         hw->clip (dst, src, convert_samples);
-        qemu_put_buffer (wav->f, dst, convert_samples << hw->shift);
-        memset (src, 0, convert_samples * sizeof (st_sample_t));
+        qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
+        mixeng_clear (src, convert_samples);
 
         rpos = (rpos + convert_samples) % hw->samples;
         samples -= convert_samples;
         wav->total_samples += convert_samples;
     }
 
-    pcm_hw_dec_live (hw, decr);
     hw->rpos = rpos;
+    return decr;
 }
 
-static int wav_hw_write (SWVoice *sw, void *buf, int len)
+static int wav_write_out (SWVoiceOut *sw, void *buf, int len)
 {
-    return pcm_hw_write (sw, buf, len);
+    return audio_pcm_sw_write (sw, buf, len);
 }
 
 /* VICE code: Store number as little endian. */
@@ -104,20 +107,25 @@ static void le_store (uint8_t *buf, uint32_t val, int len)
     }
 }
 
-static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
+static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
 {
-    WAVVoice *wav = (WAVVoice *) hw;
-    int bits16 = 0, stereo = audio_state.fixed_channels == 2;
+    WAVVoiceOut *wav = (WAVVoiceOut *) hw;
+    int bits16 = 0, stereo = 0;
     uint8_t hdr[] = {
         0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
         0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
         0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
         0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
     };
+    audsettings_t wav_as = conf.settings;
 
-    switch (audio_state.fixed_fmt) {
+    (void) as;
+
+    stereo = wav_as.nchannels == 2;
+    switch (wav_as.fmt) {
     case AUD_FMT_S8:
     case AUD_FMT_U8:
+        bits16 = 0;
         break;
 
     case AUD_FMT_S16:
@@ -127,22 +135,25 @@ static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
     }
 
     hdr[34] = bits16 ? 0x10 : 0x08;
-    hw->freq = 44100;
-    hw->nchannels = stereo ? 2 : 1;
-    hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
-    hw->bufsize = 4096;
-    wav->pcm_buf = qemu_mallocz (hw->bufsize);
-    if (!wav->pcm_buf)
+
+    audio_pcm_init_info (&hw->info, &wav_as, audio_need_to_swap_endian (0));
+
+    hw->samples = 1024;
+    wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+    if (!wav->pcm_buf) {
+        dolog ("Could not allocate buffer (%d bytes)\n",
+               hw->samples << hw->info.shift);
         return -1;
+    }
 
-    le_store (hdr + 22, hw->nchannels, 2);
-    le_store (hdr + 24, hw->freq, 4);
-    le_store (hdr + 28, hw->freq << (bits16 + stereo), 4);
+    le_store (hdr + 22, hw->info.nchannels, 2);
+    le_store (hdr + 24, hw->info.freq, 4);
+    le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
     le_store (hdr + 32, 1 << (bits16 + stereo), 2);
 
     wav->f = fopen (conf.wav_path, "wb");
     if (!wav->f) {
-        dolog ("failed to open wave file `%s'\nReason: %s\n",
+        dolog ("Failed to open wave file `%s'\nReason: %s\n",
                conf.wav_path, strerror (errno));
         qemu_free (wav->pcm_buf);
         wav->pcm_buf = NULL;
@@ -153,17 +164,17 @@ static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
     return 0;
 }
 
-static void wav_hw_fini (HWVoice *hw)
+static void wav_fini_out (HWVoiceOut *hw)
 {
-    WAVVoice *wav = (WAVVoice *) hw;
-    int stereo = hw->nchannels == 2;
+    WAVVoiceOut *wav = (WAVVoiceOut *) hw;
     uint8_t rlen[4];
     uint8_t dlen[4];
-    uint32_t rifflen = (wav->total_samples << stereo) + 36;
-    uint32_t datalen = wav->total_samples << stereo;
+    uint32_t datalen = wav->total_samples << hw->info.shift;
+    uint32_t rifflen = datalen + 36;
 
-    if (!wav->f || !hw->active)
+    if (!wav->f) {
         return;
+    }
 
     le_store (rlen, rifflen, 4);
     le_store (dlen, datalen, 4);
@@ -181,7 +192,7 @@ static void wav_hw_fini (HWVoice *hw)
     wav->pcm_buf = NULL;
 }
 
-static int wav_hw_ctl (HWVoice *hw, int cmd, ...)
+static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
 {
     (void) hw;
     (void) cmd;
@@ -195,23 +206,50 @@ static void *wav_audio_init (void)
 
 static void wav_audio_fini (void *opaque)
 {
+    (void) opaque;
     ldebug ("wav_fini");
 }
 
-struct pcm_ops wav_pcm_ops = {
-    wav_hw_init,
-    wav_hw_fini,
-    wav_hw_run,
-    wav_hw_write,
-    wav_hw_ctl
+struct audio_option wav_options[] = {
+    {"FREQUENCY", AUD_OPT_INT, &conf.settings.freq,
+     "Frequency", NULL, 0},
+
+    {"FORMAT", AUD_OPT_FMT, &conf.settings.fmt,
+     "Format", NULL, 0},
+
+    {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels,
+     "Number of channels (1 - mono, 2 - stereo)", NULL, 0},
+
+    {"PATH", AUD_OPT_STR, &conf.wav_path,
+     "Path to wave file", NULL, 0},
+    {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+struct audio_pcm_ops wav_pcm_ops = {
+    wav_init_out,
+    wav_fini_out,
+    wav_run_out,
+    wav_write_out,
+    wav_ctl_out,
+
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL
 };
 
-struct audio_output_driver wav_output_driver = {
-    "wav",
-    wav_audio_init,
-    wav_audio_fini,
-    &wav_pcm_ops,
-    1,
-    1,
-    sizeof (WAVVoice)
+struct audio_driver wav_audio_driver = {
+    INIT_FIELD (name           = ) "wav",
+    INIT_FIELD (descr          = )
+    "WAV renderer http://wikipedia.org/wiki/WAV",
+    INIT_FIELD (options        = ) wav_options,
+    INIT_FIELD (init           = ) wav_audio_init,
+    INIT_FIELD (fini           = ) wav_audio_fini,
+    INIT_FIELD (pcm_ops        = ) &wav_pcm_ops,
+    INIT_FIELD (can_be_default = ) 0,
+    INIT_FIELD (max_voices_out = ) 1,
+    INIT_FIELD (max_voices_in  = ) 0,
+    INIT_FIELD (voice_size_out = ) sizeof (WAVVoiceOut),
+    INIT_FIELD (voice_size_in  = ) 0
 };
index ca05be8..34026a4 100644 (file)
@@ -552,25 +552,28 @@ static int qcow_create(const char *filename, int64_t total_size,
     header_size = sizeof(header);
     backing_filename_len = 0;
     if (backing_file) {
-        const char *p;
-        /* XXX: this is a hack: we do not attempt to check for URL
-           like syntax */
-        p = strchr(backing_file, ':');
-        if (p && (p - backing_file) >= 2) {
-            /* URL like but exclude "c:" like filenames */
-            pstrcpy(backing_filename, sizeof(backing_filename),
-                    backing_file);
-        } else {
-            realpath(backing_file, backing_filename);
-            if (stat(backing_filename, &st) != 0) {
-                return -1;
-            }
-        }
+       if (strcmp(backing_file, "fat:")) {
+           const char *p;
+           /* XXX: this is a hack: we do not attempt to check for URL
+              like syntax */
+           p = strchr(backing_file, ':');
+           if (p && (p - backing_file) >= 2) {
+               /* URL like but exclude "c:" like filenames */
+               pstrcpy(backing_filename, sizeof(backing_filename),
+                       backing_file);
+           } else {
+               realpath(backing_file, backing_filename);
+               if (stat(backing_filename, &st) != 0) {
+                   return -1;
+               }
+           }
+           header.backing_file_offset = cpu_to_be64(header_size);
+           backing_filename_len = strlen(backing_filename);
+           header.backing_file_size = cpu_to_be32(backing_filename_len);
+           header_size += backing_filename_len;
+       } else
+           backing_file = NULL;
         header.mtime = cpu_to_be32(st.st_mtime);
-        header.backing_file_offset = cpu_to_be64(header_size);
-        backing_filename_len = strlen(backing_filename);
-        header.backing_file_size = cpu_to_be32(backing_filename_len);
-        header_size += backing_filename_len;
         header.cluster_bits = 9; /* 512 byte cluster to avoid copying
                                     unmodifyed sectors */
         header.l2_bits = 12; /* 32 KB L2 tables */
@@ -603,6 +606,24 @@ static int qcow_create(const char *filename, int64_t total_size,
     return 0;
 }
 
+int qcow_make_empty(BlockDriverState *bs)
+{
+    BDRVQcowState *s = bs->opaque;
+    uint32_t l1_length = s->l1_size * sizeof(uint64_t);
+
+    memset(s->l1_table, 0, l1_length);
+    lseek(s->fd, s->l1_table_offset, SEEK_SET);
+    if (write(s->fd, s->l1_table, l1_length) < 0)
+       return -1;
+    ftruncate(s->fd, s->l1_table_offset + l1_length);
+
+    memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
+    memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
+    memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t));
+
+    return 0;
+}
+
 int qcow_get_cluster_size(BlockDriverState *bs)
 {
     BDRVQcowState *s = bs->opaque;
@@ -683,6 +704,7 @@ BlockDriver bdrv_qcow = {
     qcow_create,
     qcow_is_allocated,
     qcow_set_key,
+    qcow_make_empty
 };
 
 
index 3bbd149..fc87be3 100644 (file)
@@ -123,8 +123,8 @@ static int vmdk_open(BlockDriverState *bs, const char *filename)
         
         if (read(fd, &header, sizeof(header)) != sizeof(header))
             goto fail;
-        bs->total_sectors = le32_to_cpu(header.capacity);
-        s->cluster_sectors = le32_to_cpu(header.granularity);
+        bs->total_sectors = le64_to_cpu(header.capacity);
+        s->cluster_sectors = le64_to_cpu(header.granularity);
         s->l2_size = le32_to_cpu(header.num_gtes_per_gte);
         s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
         if (s->l1_entry_sectors <= 0)
index 7bce91e..36f9713 100644 (file)
@@ -1,7 +1,8 @@
+/* vim:set shiftwidth=4 ts=8: */
 /*
  * QEMU Block driver for virtual VFAT (shadows a local directory)
  * 
- * Copyright (c) 2004 Johannes E. Schindelin
+ * 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
 #include "vl.h"
 #include "block_int.h"
 
-// TODO: new file
-// TODO: delete file
-// TODO: make root directory larger
-// TODO: make directory clusters connected, so they are reserved anyway... add a member which tells how many clusters are reserved after a directory
-// TODO: introduce another member in mapping_t which says where the directory resides in s->directory (for mkdir and rmdir) 
-// in _read and _write, before treating direntries or file contents, get_mapping to know what it is.
-// TODO: mkdir
-// TODO: rmdir 
+#ifndef S_IWGRP
+#define S_IWGRP 0
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 0
+#endif
+
+/* 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 
+    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 */
+
+/* #define DEBUG */
+
+#ifdef DEBUG
+
+#define DLOG(a) a
+
+#undef stderr
+#define stderr STDERR
+FILE* stderr = NULL;
 
-// TODO: when commit_data'ing a direntry and is_consistent, commit_remove
-// TODO: reset MODE_MODIFIED when commit_remove'ing
+static void checkpoint();
 
-#define DEBUG
+#ifdef __MINGW32__
+void nonono(const char* file, int line, const char* msg) {
+    fprintf(stderr, "Nonono! %s:%d %s\n", file, line, msg);
+    exit(-5);
+}
+#undef assert
+#define assert(a) if (!(a)) nonono(__FILE__, __LINE__, #a)
+#endif
+
+#else
+
+#define DLOG(a)
+
+#endif
 
 /* dynamic array functions */
 typedef struct array_t {
@@ -62,23 +91,37 @@ static inline void array_free(array_t* array)
     array->size=array->next=0;
 }
 
-/* make sure that memory is reserved at pointer[index*item_size] */
+/* does not automatically grow */
 static inline void* array_get(array_t* array,unsigned int index) {
-    if((index+1)*array->item_size>array->size) {
-       int new_size=(index+32)*array->item_size;
-       array->pointer=realloc(array->pointer,new_size);
-       if(!array->pointer)
-           return 0;
-       array->size=new_size;
-       array->next=index+1;
+    assert(index >= 0);
+    assert(index < array->next);
+    return array->pointer + index * array->item_size;
+}
+
+static inline int array_ensure_allocated(array_t* array, int index)
+{
+    if((index + 1) * array->item_size > array->size) {
+       int new_size = (index + 32) * array->item_size;
+       array->pointer = realloc(array->pointer, new_size);
+       if (!array->pointer)
+           return -1;
+       array->size = new_size;
+       array->next = index + 1;
     }
-    return array->pointer+index*array->item_size;
+
+    return 0;
 }
 
 static inline void* array_get_next(array_t* array) {
-    unsigned int next=array->next;
-    void* result=array_get(array,next);
-    array->next=next+1;
+    unsigned int next = array->next;
+    void* result;
+
+    if (array_ensure_allocated(array, next) < 0)
+       return NULL;
+
+    array->next = next + 1;
+    result = array_get(array, next);
+
     return result;
 }
 
@@ -132,14 +175,32 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun
     return 0;
 }
 
-int array_remove(array_t* array,int index)
+inline int array_remove_slice(array_t* array,int index, int count)
 {
-    if(array_roll(array,array->next-1,index,1))
+    assert(index >=0);
+    assert(count > 0);
+    assert(index + count <= array->next);
+    if(array_roll(array,array->next-1,index,count))
        return -1;
-    array->next--;
+    array->next -= count;
     return 0;
 }
 
+int array_remove(array_t* array,int index)
+{
+    return array_remove_slice(array, index, 1);
+}
+
+/* return the index for a given member */
+int array_index(array_t* array, void* pointer)
+{
+    size_t offset = (char*)pointer - array->pointer;
+    assert(offset >= 0);
+    assert((offset % array->item_size) == 0);
+    assert(offset/array->item_size < array->next);
+    return offset/array->item_size;
+}
+
 /* These structures are used to fake a disk and the VFAT filesystem.
  * For this reason we need to use __attribute__((packed)). */
 
@@ -151,7 +212,7 @@ typedef struct bootsector_t {
     uint16_t reserved_sectors;
     uint8_t number_of_fats;
     uint16_t root_entries;
-    uint16_t zero;
+    uint16_t total_sectors16;
     uint8_t media_type;
     uint16_t sectors_per_fat;
     uint16_t sectors_per_track;
@@ -186,7 +247,7 @@ typedef struct partition_t {
     uint8_t start_head;
     uint8_t start_sector;
     uint8_t start_cylinder;
-    uint8_t fs_type; /* 0x6 = FAT16, 0xb = FAT32 */
+    uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */
     uint8_t end_head;
     uint8_t end_sector;
     uint8_t end_cylinder;
@@ -218,32 +279,44 @@ typedef struct direntry_t {
 /* this structure are used to transparently access the files */
 
 typedef struct mapping_t {
-    /* begin is the first cluster, end is the last+1,
-     * offset is the offset in the file in clusters of this slice */
-    off_t begin,end,offset;
-    char* filename;
-
+    /* begin is the first cluster, end is the last+1 */
+    uint32_t begin,end;
     /* as s->directory is growable, no pointer may be used here */
     unsigned int dir_index;
-    enum { MODE_NORMAL,MODE_UNDEFINED,MODE_MODIFIED,MODE_DELETED,MODE_DIRECTORY } mode;
+    /* the clusters of a file may be in any order; this points to the first */
+    int first_mapping_index;
+    union {
+       /* offset is
+        * - the offset in the file (in clusters) for a file, or
+        * - the next cluster of the directory for a directory, and
+        * - the address of the buffer for a faked entry
+        */
+       struct {
+           uint32_t offset;
+       } file;
+       struct {
+           int parent_mapping_index;
+           int first_dir_index;
+       } dir;
+    } info;
+    /* path contains the full path, i.e. it always starts with s->path */
+    char* path;
+
+    enum { MODE_UNDEFINED = 0, MODE_NORMAL = 1, MODE_MODIFIED = 2,
+       MODE_DIRECTORY = 4, MODE_FAKED = 8,
+       MODE_DELETED = 16, MODE_RENAMED = 32 } mode;
+    int read_only;
 } mapping_t;
 
-/* this structure is used to hold sectors which need to be written, but it's
- * not known yet where to write them. */
-
-typedef struct commit_t {
-    uint32_t cluster_num;
-    uint8_t* buf;
-} commit_t;
-
-/* write support exists for fat, direntry and file contents */
-typedef enum {
-    WRITE_UNDEFINED,WRITE_FAT,WRITE_DIRENTRY,WRITE_DATA
-} write_action_t;
+#ifdef DEBUG
+static void print_direntry(const struct direntry_t*);
+static void print_mapping(const struct mapping_t* mapping);
+#endif
 
 /* here begins the real VVFAT driver */
 
 typedef struct BDRVVVFATState {
+    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];
     
@@ -254,31 +327,33 @@ typedef struct BDRVVVFATState {
     unsigned int sectors_per_cluster;
     unsigned int sectors_per_fat;
     unsigned int sectors_of_root_directory;
-    unsigned int sectors_for_directory;
+    uint32_t last_cluster_of_root_directory;
     unsigned int faked_sectors; /* how many sectors are faked before file data */
     uint32_t sector_count; /* total number of sectors of the partition */
     uint32_t cluster_count; /* total number of clusters of this partition */
-    unsigned int first_file_mapping; /* index of the first mapping which is not a directory, but a file */
     uint32_t max_fat_value;
    
     int current_fd;
-    char current_fd_is_writable; /* =0 if read only, !=0 if read/writable */
     mapping_t* current_mapping;
-    unsigned char* cluster;
+    unsigned char* cluster; /* points to current cluster */
+    unsigned char* cluster_buffer; /* points to a buffer to hold temp data */
     unsigned int current_cluster;
 
     /* write support */
-    array_t commit;
-    /* for each file, the file contents, the direntry, and the fat entries are
-     * written, but not necessarily in that order */
-    write_action_t action[3];
+    BlockDriverState* write_target;
+    char* qcow_filename;
+    BlockDriverState* qcow;
+    void* fat2;
+    char* used_clusters;
+    array_t commits;
+    const char* path;
+    int downcase_short_names;
 } BDRVVVFATState;
 
 
 static int vvfat_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
-    if (strstart(filename, "fat:", NULL) ||
-        strstart(filename, "fatrw:", NULL))
+    if (strstart(filename, "fat:", NULL))
        return 100;
     return 0;
 }
@@ -295,16 +370,19 @@ static void init_mbr(BDRVVVFATState* s)
     partition->start_head=1;
     partition->start_sector=1;
     partition->start_cylinder=0;
-    partition->fs_type=(s->fat_type==16?0x6:0xb); /* FAT16/FAT32 */
-    partition->end_head=0xf;
+    /* 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(0x3f);
+    partition->start_sector_long=cpu_to_le32(s->bs->secs);
     partition->end_sector_long=cpu_to_le32(s->sector_count);
 
     real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
 }
 
+/* direntry functions */
+
 /* dest is assumed to hold 258 bytes, and pads with 0xffff up to next multiple of 26 */
 static inline int short2long_name(unsigned char* dest,const char* src)
 {
@@ -344,9 +422,62 @@ static inline direntry_t* create_long_filename(BDRVVVFATState* s,const char* fil
     return array_get(&(s->directory),s->directory.next-number_of_entries);
 }
 
+static char is_free(const direntry_t* direntry)
+{
+    /* return direntry->name[0]==0 ; */
+    return direntry->attributes == 0 || direntry->name[0]==0xe5;
+}
+
+static char is_volume_label(const direntry_t* direntry)
+{
+    return direntry->attributes == 0x28;
+}
+
+static char is_long_name(const direntry_t* direntry)
+{
+    return direntry->attributes == 0xf;
+}
+
+static char is_short_name(const direntry_t* direntry)
+{
+    return !is_volume_label(direntry) && !is_long_name(direntry)
+       && !is_free(direntry);
+}
+
+static char is_directory(const direntry_t* direntry)
+{
+    return direntry->attributes & 0x10 && direntry->name[0] != 0xe5;
+}
+
+static inline char is_dot(const direntry_t* direntry)
+{
+    return is_short_name(direntry) && direntry->name[0] == '.';
+}
+
+static char is_file(const direntry_t* direntry)
+{
+    return is_short_name(direntry) && !is_directory(direntry);
+}
+
+static inline uint32_t begin_of_direntry(const direntry_t* direntry)
+{
+    return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
+}
+
+static inline uint32_t filesize_of_direntry(const direntry_t* direntry)
+{
+    return le32_to_cpu(direntry->size);
+}
+
+static void set_begin_of_direntry(direntry_t* direntry, uint32_t begin)
+{
+    direntry->begin = cpu_to_le16(begin & 0xffff);
+    direntry->begin_hi = cpu_to_le16((begin >> 16) & 0xffff);
+}
+
 /* fat functions */
 
-static inline uint8_t fat_chksum(direntry_t* entry)
+static inline uint8_t fat_chksum(const direntry_t* entry)
 {
     uint8_t chksum=0;
     int i;
@@ -375,29 +506,39 @@ static uint16_t fat_datetime(time_t time,int return_time) {
 
 static inline void fat_set(BDRVVVFATState* s,unsigned int cluster,uint32_t value)
 {
-    if(s->fat_type==12) {
-       assert(0); /* TODO */
+    if(s->fat_type==32) {
+       uint32_t* entry=array_get(&(s->fat),cluster);
+       *entry=cpu_to_le32(value);
     } else if(s->fat_type==16) {
        uint16_t* entry=array_get(&(s->fat),cluster);
        *entry=cpu_to_le16(value&0xffff);
     } else {
-       uint32_t* entry=array_get(&(s->fat),cluster);
-       *entry=cpu_to_le32(value);
+       int offset = (cluster*3/2);
+       unsigned char* p = array_get(&(s->fat), offset);
+        switch (cluster&1) {
+       case 0:
+               p[0] = value&0xff;
+               p[1] = (p[1]&0xf0) | ((value>>8)&0xf);
+               break;
+       case 1:
+               p[0] = (p[0]&0xf) | ((value&0xf)<<4);
+               p[1] = (value>>4);
+               break;
+       }
     }
 }
 
 static inline uint32_t fat_get(BDRVVVFATState* s,unsigned int cluster)
 {
-    //fprintf(stderr,"want to get fat for cluster %d\n",cluster);
-    if(s->fat_type==12) {
-       const uint8_t* x=s->fat.pointer+cluster*3/2;
-       return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
+    if(s->fat_type==32) {
+       uint32_t* entry=array_get(&(s->fat),cluster);
+       return le32_to_cpu(*entry);
     } else if(s->fat_type==16) {
        uint16_t* entry=array_get(&(s->fat),cluster);
        return le16_to_cpu(*entry);
     } else {
-       uint32_t* entry=array_get(&(s->fat),cluster);
-       return le32_to_cpu(*entry);
+       const uint8_t* x=s->fat.pointer+cluster*3/2;
+       return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
     }
 }
 
@@ -410,69 +551,32 @@ static inline int fat_eof(BDRVVVFATState* s,uint32_t fat_entry)
 
 static inline void init_fat(BDRVVVFATState* s)
 {
-    int i;
-    
-    array_init(&(s->fat),(s->fat_type==32?4:2));
-    array_get(&(s->fat),s->sectors_per_fat*0x200/s->fat.item_size-1);
+    if (s->fat_type == 12) {
+       array_init(&(s->fat),1);
+       array_ensure_allocated(&(s->fat),
+               s->sectors_per_fat * 0x200 * 3 / 2 - 1);
+    } else {
+       array_init(&(s->fat),(s->fat_type==32?4:2));
+       array_ensure_allocated(&(s->fat),
+               s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
+    }
     memset(s->fat.pointer,0,s->fat.size);
-    fat_set(s,0,0x7ffffff8);
     
-    for(i=1;i<s->sectors_for_directory/s->sectors_per_cluster-1;i++)
-       fat_set(s,i,i+1);
-    fat_set(s,i,0x7fffffff);
-
     switch(s->fat_type) {
        case 12: s->max_fat_value=0xfff; break;
        case 16: s->max_fat_value=0xffff; break;
-       case 32: s->max_fat_value=0xfffffff; break;
+       case 32: s->max_fat_value=0x0fffffff; break;
        default: s->max_fat_value=0; /* error... */
     }
 
 }
 
-static inline int long2unix_name(unsigned char* dest,int dest_size,direntry_t* direntry_short) {
-    int i=-1,j;
-    int chksum=fat_chksum(direntry_short);
-    while(1) {
-       char* buf=(char*)(direntry_short+i);
-       if((buf[0]&0x3f)!=-i || direntry_short[i].reserved[1]!=chksum ||
-               direntry_short[i].attributes!=0xf) {
-           if(i<-1)
-               return -3;
-           /* take short name */
-           for(j=7;j>0 && direntry_short->name[j]==' ';j--);
-           if(j+1>dest_size)
-               return -1;
-           strncpy(dest,direntry_short->name,j+1);
-           dest+=j+1; dest_size-=j+1;
-           for(j=2;j>=0 && direntry_short->extension[j]==' ';j--);
-           if(j>=0) {
-               if(j+2>dest_size)
-                   return -1;
-               dest[0]='.';
-               strncpy(dest+1,direntry_short->extension,j+1);
-           }
-           return 0;
-       }
-       for(j=0;j<13;j++) {
-           dest_size--;
-           if(dest_size<0)
-               return -2;
-           dest[0]=buf[2*j+((j<5)?1:(j<11)?4:6)];
-           if(dest[0]==0 && (buf[0]&0x40)!=0)
-               return 0;
-           dest++;
-       }
-       /* last entry, but no trailing \0? */
-       if(buf[0]&0x40)
-           return -3;
-       i--;
-    }
-}
-
-static inline direntry_t* create_short_filename(BDRVVVFATState* s,unsigned int directory_start,const char* filename,int is_dot)
+/* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
+/* TODO: in parse_short_filename, 0x05->0xe5 is not yet handled! */
+static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
+       unsigned int directory_start, const char* filename, int is_dot)
 {
-    int i,long_index=s->directory.next;
+    int i,j,long_index=s->directory.next;
     direntry_t* entry=0;
     direntry_t* entry_long=0;
 
@@ -483,26 +587,28 @@ static inline direntry_t* create_short_filename(BDRVVVFATState* s,unsigned int d
        return entry;
     }
     
-    for(i=1;i<8 && filename[i] && filename[i]!='.';i++);
-
     entry_long=create_long_filename(s,filename);
-   
+  
+    i = strlen(filename); 
+    for(j = i - 1; j>0  && filename[j]!='.';j--);
+    if (j > 0)
+       i = (j > 8 ? 8 : j);
+    else if (i > 8)
+       i = 8;
+
     entry=array_get_next(&(s->directory));
     memset(entry->name,0x20,11);
     strncpy(entry->name,filename,i);
     
-    if(filename[i]) {
-       int len=strlen(filename);
-        for(i=len;i>0 && filename[i-1]!='.';i--);
-        if(i>0)
-            memcpy(entry->extension,filename+i,(len-i>3?3:len-i));
-    }
+    if(j > 0)
+       for (i = 0; i < 3 && filename[j+1+i]; i++)
+           entry->extension[i] = filename[j+1+i];
 
     /* upcase & remove unwanted characters */
     for(i=10;i>=0;i--) {
-       if(i==10 || i==7) for(;i>1 && entry->name[i]==' ';i--);
+       if(i==10 || i==7) for(;i>0 && entry->name[i]==' ';i--);
        if(entry->name[i]<=' ' || entry->name[i]>0x7f
-               || strchr("*?<>|\":/\\[];,+='",entry->name[i]))
+               || strchr(".*?<>|\":/\\[];,+='",entry->name[i]))
            entry->name[i]='_';
         else if(entry->name[i]>='a' && entry->name[i]<='z')
             entry->name[i]+='A'-'a';
@@ -514,7 +620,7 @@ static inline direntry_t* create_short_filename(BDRVVVFATState* s,unsigned int d
        int j;
 
        for(;entry1<entry;entry1++)
-           if(!(entry1->attributes&0xf) && !memcmp(entry1->name,entry->name,11))
+           if(!is_long_name(entry1) && !memcmp(entry1->name,entry->name,11))
                break; /* found dupe */
        if(entry1==entry) /* no dupe found */
            break;
@@ -543,8 +649,7 @@ static inline direntry_t* create_short_filename(BDRVVVFATState* s,unsigned int d
 
        /* calculate anew, because realloc could have taken place */
        entry_long=array_get(&(s->directory),long_index);
-       while(entry_long<entry
-                   && entry_long->attributes==0xf) {
+       while(entry_long<entry && is_long_name(entry_long)) {
            entry_long->reserved[1]=chksum;
            entry_long++;
        }
@@ -553,33 +658,48 @@ static inline direntry_t* create_short_filename(BDRVVVFATState* s,unsigned int d
     return entry;
 }
 
-static int read_directory(BDRVVVFATState* s,const char* dirname,
-               int first_cluster_of_parent)
+/*
+ * Read a directory. (the index of the corresponding mapping must be passed).
+ */
+static int read_directory(BDRVVVFATState* s, int mapping_index)
 {
+    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
+    direntry_t* direntry;
+    const char* dirname = mapping->path;
+    int first_cluster = mapping->begin;
+    int parent_index = mapping->info.dir.parent_mapping_index;
+    mapping_t* parent_mapping = (mapping_t*)
+       (parent_index >= 0 ? array_get(&(s->mapping), parent_index) : 0);
+    int first_cluster_of_parent = parent_mapping ? parent_mapping->begin : -1;
 
     DIR* dir=opendir(dirname);
     struct dirent* entry;
-    struct stat st;
-    unsigned int start_of_directory=s->directory.next;
-    /* mappings before first_file_mapping are directories */
-    unsigned int first_directory_mapping=s->first_file_mapping;
-    unsigned int first_cluster=(start_of_directory/0x10/s->sectors_per_cluster);
     int i;
 
-    if(!dir)
+    assert(mapping->mode & MODE_DIRECTORY);
+
+    if(!dir) {
+       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 */ 
     while((entry=readdir(dir))) {
        unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
         char* buffer;
        direntry_t* direntry;
+        struct stat st;
        int is_dot=!strcmp(entry->d_name,".");
        int is_dotdot=!strcmp(entry->d_name,"..");
 
-       if(start_of_directory==1 && (is_dotdot || is_dot))
+       if(first_cluster == 0 && (is_dotdot || is_dot))
            continue;
        
        buffer=(char*)malloc(length);
+       assert(buffer);
        snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
 
        if(stat(buffer,&st)<0) {
@@ -588,8 +708,8 @@ static int read_directory(BDRVVVFATState* s,const char* dirname,
        }
 
        /* create directory entry for this file */
-       //fprintf(stderr,"create direntry at %d (cluster %d) for %s\n",s->directory.next,s->directory.next/0x10/s->sectors_per_cluster,entry->d_name);
-       direntry=create_short_filename(s,start_of_directory,entry->d_name,is_dot||is_dotdot);
+       direntry=create_short_and_long_name(s, i, entry->d_name,
+               is_dot || is_dotdot);
        direntry->attributes=(S_ISDIR(st.st_mode)?0x10:0x20);
        direntry->reserved[0]=direntry->reserved[1]=0;
        direntry->ctime=fat_datetime(st.st_ctime,1);
@@ -599,25 +719,40 @@ static int read_directory(BDRVVVFATState* s,const char* dirname,
        direntry->mtime=fat_datetime(st.st_mtime,1);
        direntry->mdate=fat_datetime(st.st_mtime,0);
        if(is_dotdot)
-           direntry->begin=cpu_to_le16(first_cluster_of_parent);
+           set_begin_of_direntry(direntry, first_cluster_of_parent);
        else if(is_dot)
-           direntry->begin=cpu_to_le16(first_cluster);
+           set_begin_of_direntry(direntry, first_cluster);
        else
-           direntry->begin=cpu_to_le16(0); /* do that later */
-       direntry->size=cpu_to_le32(st.st_size);
+           direntry->begin=0; /* do that later */
+        if (st.st_size > 0x7fffffff) {
+           fprintf(stderr, "File %s is larger than 2GB\n", buffer);
+           free(buffer);
+           return -2;
+        }
+       direntry->size=cpu_to_le32(S_ISDIR(st.st_mode)?0:st.st_size);
 
        /* create mapping for this file */
-       if(!is_dot && !is_dotdot) {
-           if(S_ISDIR(st.st_mode))
-               s->current_mapping=(mapping_t*)array_insert(&(s->mapping),s->first_file_mapping++,1);
-           else
-               s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
+       if(!is_dot && !is_dotdot && (S_ISDIR(st.st_mode) || st.st_size)) {
+           s->current_mapping=(mapping_t*)array_get_next(&(s->mapping));
            s->current_mapping->begin=0;
            s->current_mapping->end=st.st_size;
-           s->current_mapping->offset=0;
-           s->current_mapping->filename=buffer;
+           /*
+            * we get the direntry of the most recent direntry, which
+            * contains the short name and all the relevant information.
+            */
            s->current_mapping->dir_index=s->directory.next-1;
-           s->current_mapping->mode=(S_ISDIR(st.st_mode)?MODE_DIRECTORY:MODE_UNDEFINED);
+           s->current_mapping->first_mapping_index = -1;
+           if (S_ISDIR(st.st_mode)) {
+               s->current_mapping->mode = MODE_DIRECTORY;
+               s->current_mapping->info.dir.parent_mapping_index =
+                   mapping_index;
+           } else {
+               s->current_mapping->mode = MODE_UNDEFINED;
+               s->current_mapping->info.file.offset = 0;
+           }
+           s->current_mapping->path=buffer;
+           s->current_mapping->read_only =
+               (st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0;
        }
     }
     closedir(dir);
@@ -628,89 +763,78 @@ static int read_directory(BDRVVVFATState* s,const char* dirname,
        memset(direntry,0,sizeof(direntry_t));
     }
 
-    /* reserve next cluster also (for new files) */
-    for(i=0;i<0x10*s->sectors_per_cluster;i++) {
-       direntry_t* direntry=array_get_next(&(s->directory));
-       memset(direntry,0,sizeof(direntry_t));
-    }
-
-    /* was it the first directory? */
-    if(start_of_directory==1) {
-       mapping_t* mapping=array_insert(&(s->mapping),0,1);
-       mapping->filename=strdup(dirname);
-       mapping->mode=MODE_DIRECTORY;
-       mapping->begin=0;
-       mapping->end=1;
-       mapping->offset=0;
-       mapping->dir_index=0xffffffff;
-       s->sectors_of_root_directory=s->directory.next/0x10;
+/* TODO: if there are more entries, bootsector has to be adjusted! */
+#define ROOT_ENTRIES (0x02 * 0x10 * s->sectors_per_cluster)
+    if (mapping_index == 0 && s->directory.next < ROOT_ENTRIES) {
+       /* root directory */
+       int cur = s->directory.next;
+       array_ensure_allocated(&(s->directory), ROOT_ENTRIES - 1);
+       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)
+       * 0x20 / s->cluster_size;
+    mapping->end = first_cluster;
+
+    direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
+    set_begin_of_direntry(direntry, mapping->begin);
+   
+    return 0;
+}
 
-    /* recurse directories */
-    {
-       int i;
-
-       //fprintf(stderr,"iterating subdirectories of %s (first cluster %d): %d to %d\n",dirname,first_cluster,first_directory_mapping,last_directory_mapping);
-       for(i=first_directory_mapping;i<s->first_file_mapping;i++) {
-           mapping_t* mapping=array_get(&(s->mapping),i);
-           direntry_t* direntry=array_get(&(s->directory),mapping->dir_index);
-           /* the directory to be read can add more subdirectories */
-           int last_dir_mapping=s->first_file_mapping;
-           
-           assert(mapping->mode==MODE_DIRECTORY);
-           /* first, tell the mapping where the directory will start */
-           mapping->begin=s->directory.next/0x10/s->sectors_per_cluster;
-           if(i>0) {
-               mapping[-1].end=mapping->begin;
-               assert(mapping[-1].begin<mapping->begin);
-           }
-           /* then tell the direntry */
-           direntry->begin=cpu_to_le16(mapping->begin);
-           //fprintf(stderr,"read directory %s (begin %d)\n",mapping->filename,(int)mapping->begin);
-           /* then read it */
-           if(read_directory(s,mapping->filename,first_cluster))
-               return -1;
-
-           if(last_dir_mapping!=s->first_file_mapping) {
-               int diff=s->first_file_mapping-last_dir_mapping;
-               assert(diff>0);
+static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
+{
+    return (sector_num-s->faked_sectors)/s->sectors_per_cluster;
+}
 
-               if(last_dir_mapping!=i+1) {
-                   int count=last_dir_mapping-i-1;
-                   int to=s->first_file_mapping-count;
+static inline off_t cluster2sector(BDRVVVFATState* s, uint32_t cluster_num)
+{
+    return s->faked_sectors + s->sectors_per_cluster * cluster_num;
+}
 
-                   assert(count>0);
-                   assert(to>i+1);
-                   array_roll(&(s->mapping),to,i+1,count);
-                   /* could have changed due to realloc */
-                   mapping=array_get(&(s->mapping),i);
-                   mapping->end=mapping[1].begin;
-               }
-               i+=diff;
-           }
-       }
-    }
+static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
+{
+    return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
+}
 
-    return 0;
+#ifdef DBG
+static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
+{
+    if(mapping->mode==MODE_UNDEFINED)
+       return 0;
+    return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
 }
+#endif
 
-static int init_directory(BDRVVVFATState* s,const char* dirname)
+static int init_directories(BDRVVVFATState* s,
+       const char* dirname)
 {
-    bootsector_t* bootsector=(bootsector_t*)&(s->first_sectors[(s->first_sectors_number-1)*0x200]);
+    bootsector_t* bootsector;
+    mapping_t* mapping;
     unsigned int i;
     unsigned int cluster;
 
     memset(&(s->first_sectors[0]),0,0x40*0x200);
 
-    /* TODO: if FAT32, this is probably wrong */
-    s->sectors_per_fat=0xfc;
-    s->sectors_per_cluster=0x10;
     s->cluster_size=s->sectors_per_cluster*0x200;
-    s->cluster=malloc(s->cluster_size);
+    s->cluster_buffer=malloc(s->cluster_size);
+    assert(s->cluster_buffer);
+
+    /*
+     * The formula: sc = spf+1+spf*spc*(512*8/fat_type),
+     * where sc is sector_count,
+     * spf is sectors_per_fat,
+     * spc is sectors_per_clusters, and
+     * fat_type = 12, 16 or 32.
+     */
+    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));
-    array_init(&(s->commit),sizeof(commit_t));
 
     /* add volume label */
     {
@@ -719,69 +843,86 @@ static int init_directory(BDRVVVFATState* s,const char* dirname)
        snprintf(entry->name,11,"QEMU VVFAT");
     }
 
-    if(read_directory(s,dirname,0))
-       return -1;
-
-    /* make sure that the number of directory entries is multiple of 0x200/0x20 (to fit the last sector exactly) */
-    s->sectors_for_directory=s->directory.next/0x10;
-
-    s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2+s->sectors_for_directory;
-    s->cluster_count=(s->sector_count-s->faked_sectors)/s->sectors_per_cluster;
-
     /* Now build FAT, and write back information into directory */
     init_fat(s);
 
-    cluster=s->sectors_for_directory/s->sectors_per_cluster;
-    assert(s->sectors_for_directory%s->sectors_per_cluster==0);
-
-    /* set the end of the last read directory */
-    if(s->first_file_mapping>0) {
-       mapping_t* mapping=array_get(&(s->mapping),s->first_file_mapping-1);
-       mapping->end=cluster;
-    }
-
-    for(i=1;i<s->mapping.next;i++) {
-       mapping_t* mapping=array_get(&(s->mapping),i);
-       direntry_t* direntry=array_get(&(s->directory),mapping->dir_index);
-       if(mapping->mode==MODE_DIRECTORY) {
-           /* directory */
-           int i;
-#ifdef DEBUG
-           fprintf(stderr,"assert: %s %d < %d\n",mapping->filename,(int)mapping->begin,(int)mapping->end);
-#endif
-           assert(mapping->begin<mapping->end);
-           for(i=mapping->begin;i<mapping->end-1;i++)
-               fat_set(s,i,i+1);
-           fat_set(s,i,0x7fffffff);
-       } else {
-           /* as the space is virtual, we can be sloppy about it */
-           unsigned int end_cluster=cluster+mapping->end/s->cluster_size;
-
-           if(end_cluster>=s->cluster_count) {
-               fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
+    s->faked_sectors=s->first_sectors_number+s->sectors_per_fat*2;
+    s->cluster_count=sector2cluster(s, s->sector_count);
+
+    mapping = array_get_next(&(s->mapping));
+    mapping->begin = 0;
+    mapping->dir_index = 0;
+    mapping->info.dir.parent_mapping_index = -1;
+    mapping->first_mapping_index = -1;
+    mapping->path = strdup(dirname);
+    i = strlen(mapping->path);
+    if (i > 0 && mapping->path[i - 1] == '/')
+       mapping->path[i - 1] = '\0';
+    mapping->mode = MODE_DIRECTORY;
+    mapping->read_only = 0;
+    s->path = mapping->path;
+
+    for (i = 0, cluster = 0; i < s->mapping.next; i++) {
+       int j;
+       /* 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);
+       mapping = array_get(&(s->mapping), i);
+
+        if (mapping->mode & MODE_DIRECTORY) {
+           mapping->begin = cluster;
+           if(read_directory(s, i)) {
+               fprintf(stderr, "Could not read directory %s\n",
+                       mapping->path);
                return -1;
            }
-           mapping->begin=cluster;
+           mapping = array_get(&(s->mapping), i);
+       } else {
+           assert(mapping->mode == MODE_UNDEFINED);
            mapping->mode=MODE_NORMAL;
-           mapping->offset=0;
-           direntry->size=cpu_to_le32(mapping->end);
-           if(direntry->size==0) {
-               direntry->begin=0;
-               mapping->end=cluster;
-               continue;
+           mapping->begin = cluster;
+           if (mapping->end > 0) {
+               direntry_t* direntry = array_get(&(s->directory),
+                       mapping->dir_index);
+
+               mapping->end = cluster + 1 + (mapping->end-1)/s->cluster_size;
+               set_begin_of_direntry(direntry, mapping->begin);
+           } else {
+               mapping->end = cluster + 1;
+               fix_fat = 0;
            }
+       }
+
+       assert(mapping->begin < mapping->end);
+
+       /* fix fat for entry */
+       if (fix_fat) {
+           for(j = mapping->begin; j < mapping->end - 1; j++)
+               fat_set(s, j, j+1);
+           fat_set(s, mapping->end - 1, s->max_fat_value);
+       }
+
+       /* next free cluster */
+       cluster = mapping->end;
 
-           direntry->begin=cpu_to_le16(cluster);
-           mapping->end=end_cluster+1;
-           for(;cluster<end_cluster;cluster++)
-               fat_set(s,cluster,cluster+1);
-           fat_set(s,cluster,0x7fffffff);
-           cluster++;
+       if(cluster > s->cluster_count) {
+           fprintf(stderr,"Directory does not fit in FAT%d\n",s->fat_type);
+           return -1;
        }
     }
 
-    s->current_mapping=0;
+    mapping = array_get(&(s->mapping), 0);
+    s->sectors_of_root_directory = mapping->end * s->sectors_per_cluster;
+    s->last_cluster_of_root_directory = mapping->end;
+
+    /* the FAT signature */
+    fat_set(s,0,s->max_fat_value);
+    fat_set(s,1,s->max_fat_value);
 
+    s->current_mapping = NULL;
+
+    bootsector=(bootsector_t*)(s->first_sectors+(s->first_sectors_number-1)*0x200);
     bootsector->jump[0]=0xeb;
     bootsector->jump[1]=0x3e;
     bootsector->jump[2]=0x90;
@@ -791,17 +932,17 @@ static int init_directory(BDRVVVFATState* s,const char* dirname)
     bootsector->reserved_sectors=cpu_to_le16(1);
     bootsector->number_of_fats=0x2; /* number of FATs */
     bootsector->root_entries=cpu_to_le16(s->sectors_of_root_directory*0x10);
-    bootsector->zero=0;
-    bootsector->media_type=(s->first_sectors_number==1?0xf0:0xf8); /* media descriptor */
+    bootsector->total_sectors16=s->sector_count>0xffff?0:cpu_to_le16(s->sector_count);
+    bootsector->media_type=(s->fat_type!=12?0xf8:s->sector_count==5760?0xf9:0xf8); /* media descriptor */
+    s->fat.pointer[0] = bootsector->media_type;
     bootsector->sectors_per_fat=cpu_to_le16(s->sectors_per_fat);
-    bootsector->sectors_per_track=cpu_to_le16(0x3f);
-    bootsector->number_of_heads=cpu_to_le16(0x10);
+    bootsector->sectors_per_track=cpu_to_le16(s->bs->secs);
+    bootsector->number_of_heads=cpu_to_le16(s->bs->heads);
     bootsector->hidden_sectors=cpu_to_le32(s->first_sectors_number==1?0:0x3f);
-    /* TODO: if FAT32, adjust */
-    bootsector->total_sectors=cpu_to_le32(s->sector_count);
+    bootsector->total_sectors=cpu_to_le32(s->sector_count>0xffff?s->sector_count:0);
 
-    /* TODO: if FAT32, this is wrong */
-    bootsector->u.fat16.drive_number=0x80; /* assume this is hda (TODO) */
+    /* LATER TODO: if FAT32, this is wrong */
+    bootsector->u.fat16.drive_number=s->fat_type==12?0:0x80; /* assume this is hda (TODO) */
     bootsector->u.fat16.current_head=0;
     bootsector->u.fat16.signature=0x29;
     bootsector->u.fat16.id=cpu_to_le32(0xfabe1afd);
@@ -813,52 +954,106 @@ static int init_directory(BDRVVVFATState* s,const char* dirname)
     return 0;
 }
 
+static BDRVVVFATState *vvv = NULL;
+
+static int enable_write_target(BDRVVVFATState *s);
+static int is_consistent(BDRVVVFATState *s);
+
 static int vvfat_open(BlockDriverState *bs, const char* dirname)
 {
     BDRVVVFATState *s = bs->opaque;
+    int floppy = 0;
     int i;
 
-    /* TODO: automatically determine which FAT type */
+    vvv = s;
+
+DLOG(if (stderr == NULL) {
+    stderr = fopen("vvfat.log", "a");
+    setbuf(stderr, NULL);
+})
+
+    s->bs = bs;
+
     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;
 
     s->current_cluster=0xffffffff;
-    s->first_file_mapping=0;
 
-    /* TODO: if simulating a floppy, this is 1, because there is no partition table */
     s->first_sectors_number=0x40;
+    /* read only is the default for safety */
+    bs->read_only = 1;
+    s->qcow = s->write_target = NULL;
+    s->qcow_filename = NULL;
+    s->fat2 = NULL;
+    s->downcase_short_names = 1;
     
-    if (strstart(dirname, "fat:", &dirname)) {
-        /* read only is the default for safety */
-        bs->read_only = 1;
-    } else if (strstart(dirname, "fatrw:", &dirname)) {
-        /* development only for now */
-        bs->read_only = 0;
-    } else {
-        return -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;
+       s->first_sectors_number = 1;
+       s->sectors_per_cluster=2;
+       bs->cyls = 80; bs->heads = 2; bs->secs = 36;
+    }
+
+    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;
+    } else if (strstr(dirname, ":16:")) {
+       s->fat_type = 16;
+    } else if (strstr(dirname, ":12:")) {
+       s->fat_type = 12;
+       s->sector_count=2880;
     }
-    if(init_directory(s,dirname))
+
+    i = strrchr(dirname, ':') - dirname;
+    assert(i >= 3);
+    if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
+       /* workaround for DOS drive names */
+       dirname += i-1;
+    else
+       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;
 
     if(s->first_sectors_number==0x40)
        init_mbr(s);
 
-    /* TODO: this could be wrong for FAT32 */
-    bs->cyls=1023; bs->heads=15; bs->secs=63;
-    bs->total_sectors=bs->cyls*bs->heads*bs->secs;
+    /* for some reason or other, MS-DOS does not like to know about CHS... */
+    if (floppy)
+       bs->heads = bs->cyls = bs->secs = 0;
+
+    //    assert(is_consistent(s));
 
-    /* write support */
-    for(i=0;i<3;i++)
-       s->action[i]=WRITE_UNDEFINED;
     return 0;
 }
 
 static inline void vvfat_close_current_file(BDRVVVFATState *s)
 {
     if(s->current_mapping) {
-       s->current_mapping = 0;
-       close(s->current_fd);
+       s->current_mapping = NULL;
+       if (s->current_fd) {
+               close(s->current_fd);
+               s->current_fd = 0;
+       }
     }
+    s->current_cluster = -1;
 }
 
 /* mappings between index1 and index2-1 are supposed to be ordered
@@ -867,23 +1062,27 @@ static inline void vvfat_close_current_file(BDRVVVFATState *s)
 static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num,int index1,int index2)
 {
     int index3=index1+1;
-    //fprintf(stderr,"find_aux: cluster_num=%d, index1=%d,index2=%d\n",cluster_num,index1,index2);
     while(1) {
        mapping_t* mapping;
        index3=(index1+index2)/2;
        mapping=array_get(&(s->mapping),index3);
-       //fprintf(stderr,"index3: %d = (%d+%d)/2, end: %d\n",index3,index1,index2,(int)mapping->end);
-       if(mapping->end>cluster_num) {
+       assert(mapping->begin < mapping->end);
+       if(mapping->begin>=cluster_num) {
            assert(index2!=index3 || index2==0);
            if(index2==index3)
-               return index2;
+               return index1;
            index2=index3;
        } else {
            if(index1==index3)
-               return index2;
+               return mapping->end<=cluster_num ? index2 : index1;
            index1=index3;
        }
        assert(index1<=index2);
+       DLOG(mapping=array_get(&(s->mapping),index1);
+       assert(mapping->begin<=cluster_num);
+       assert(index2 >= s->mapping.next || 
+               ((mapping = array_get(&(s->mapping),index2)) &&
+               mapping->end>cluster_num)));
     }
 }
 
@@ -896,24 +1095,41 @@ static inline mapping_t* find_mapping_for_cluster(BDRVVVFATState* s,int cluster_
     mapping=array_get(&(s->mapping),index);
     if(mapping->begin>cluster_num)
        return 0;
+    assert(mapping->begin<=cluster_num && mapping->end>cluster_num);
     return mapping;
 }
 
-static int open_file(BDRVVVFATState* s,mapping_t* mapping,int flags)
+/*
+ * This function simply compares path == mapping->path. Since the mappings
+ * are sorted by cluster, this is expensive: O(n).
+ */
+static inline mapping_t* find_mapping_for_path(BDRVVVFATState* s,
+       const char* path)
+{
+    int i;
+
+    for (i = 0; i < s->mapping.next; i++) {
+       mapping_t* mapping = array_get(&(s->mapping), i);
+       if (mapping->first_mapping_index < 0 &&
+               !strcmp(path, mapping->path))
+           return mapping;
+    }
+
+    return NULL;
+}
+
+static int open_file(BDRVVVFATState* s,mapping_t* mapping)
 {
     if(!mapping)
        return -1;
-    assert(flags==O_RDONLY || flags==O_RDWR);
     if(!s->current_mapping ||
-           strcmp(s->current_mapping->filename,mapping->filename) ||
-           (flags==O_RDWR && !s->current_fd_is_writable)) {
+           strcmp(s->current_mapping->path,mapping->path)) {
        /* open file */
-       int fd = open(mapping->filename, flags | O_BINARY | O_LARGEFILE);
+       int fd = open(mapping->path, O_RDONLY | O_BINARY | O_LARGEFILE);
        if(fd<0)
            return -1;
        vvfat_close_current_file(s);
        s->current_fd = fd;
-       s->current_fd_is_writable = (flags==O_RDWR?-1:0);
        s->current_mapping = mapping;
     }
     return 0;
@@ -924,18 +1140,39 @@ static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
     if(s->current_cluster != cluster_num) {
        int result=0;
        off_t offset;
+       assert(!s->current_mapping || s->current_fd || (s->current_mapping->mode & MODE_DIRECTORY));
        if(!s->current_mapping
                || s->current_mapping->begin>cluster_num
                || s->current_mapping->end<=cluster_num) {
            /* binary search of mappings for file */
            mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
-           if(open_file(s,mapping,O_RDONLY))
+
+           assert(!mapping || (cluster_num>=mapping->begin && cluster_num<mapping->end));
+
+           if (mapping && mapping->mode & MODE_DIRECTORY) {
+               vvfat_close_current_file(s);
+               s->current_mapping = mapping;
+read_cluster_directory:
+               offset = s->cluster_size*(cluster_num-s->current_mapping->begin);
+               s->cluster = s->directory.pointer+offset
+                       + 0x20*s->current_mapping->info.dir.first_dir_index;
+               assert(((s->cluster-(unsigned char*)s->directory.pointer)%s->cluster_size)==0);
+               assert((char*)s->cluster+s->cluster_size <= s->directory.pointer+s->directory.next*s->directory.item_size);
+               s->current_cluster = cluster_num;
+               return 0;
+           }
+
+           if(open_file(s,mapping))
                return -2;
-       }
+       } else if (s->current_mapping->mode & MODE_DIRECTORY)
+           goto read_cluster_directory;
 
-       offset=s->cluster_size*(cluster_num-s->current_mapping->begin+s->current_mapping->offset);
+       assert(s->current_fd);
+
+       offset=s->cluster_size*(cluster_num-s->current_mapping->begin)+s->current_mapping->info.file.offset;
        if(lseek(s->current_fd, offset, SEEK_SET)!=offset)
            return -3;
+       s->cluster=s->cluster_buffer;
        result=read(s->current_fd,s->cluster,s->cluster_size);
        if(result<0) {
            s->current_cluster = -1;
@@ -946,774 +1183,1570 @@ static inline int read_cluster(BDRVVVFATState *s,int cluster_num)
     return 0;
 }
 
-static int vvfat_read(BlockDriverState *bs, int64_t sector_num, 
-                    uint8_t *buf, int nb_sectors)
+#ifdef DEBUG
+static void hexdump(const void* address, uint32_t len)
 {
-    BDRVVVFATState *s = bs->opaque;
-    int i;
-
-    //    fprintf(stderr,"vvfat_read: sector %d+%d\n",(int)sector_num,nb_sectors);
-
-    for(i=0;i<nb_sectors;i++,sector_num++) {
-       if(sector_num<s->faked_sectors) {
-               if(sector_num<s->first_sectors_number)
-                   memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
-               else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
-                       memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
-               else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
-                       memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
-               else if(sector_num-s->first_sectors_number-s->sectors_per_fat*2<s->sectors_for_directory)
-                       memcpy(buf+i*0x200,&(s->directory.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat*2)*0x200]),0x200);
-       } else {
-            uint32_t sector=sector_num-s->first_sectors_number-s->sectors_per_fat*2,
-               sector_offset_in_cluster=(sector%s->sectors_per_cluster),
-                cluster_num=sector/s->sectors_per_cluster;
-               if(read_cluster(s, cluster_num) != 0) {
-                       //fprintf(stderr,"failed to read cluster %d\n",(int)cluster_num);
-                       // TODO: strict: return -1;
-                       memset(buf+i*0x200,0,0x200);
-                       continue;
-               }
-               memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
-       }
+    const unsigned char* p = address;
+    int i, j;
+
+    for (i = 0; i < len; i += 16) {
+       for (j = 0; j < 16 && i + j < len; j++)
+           fprintf(stderr, "%02x ", p[i + j]);
+       for (; j < 16; j++)
+           fprintf(stderr, "   ");
+       fprintf(stderr, " ");
+       for (j = 0; j < 16 && i + j < len; j++)
+           fprintf(stderr, "%c", (p[i + j] < ' ' || p[i + j] > 0x7f) ? '.' : p[i + j]);
+       fprintf(stderr, "\n");
     }
-    return 0;
 }
 
-static void print_direntry(direntry_t* direntry)
+static void print_direntry(const direntry_t* direntry)
 {
+    int j = 0;
+    char buffer[1024];
+
+    fprintf(stderr, "direntry 0x%x: ", (int)direntry);
     if(!direntry)
        return;
-    if(direntry->attributes==0xf) {
+    if(is_long_name(direntry)) {
        unsigned char* c=(unsigned char*)direntry;
        int i;
        for(i=1;i<11 && c[i] && c[i]!=0xff;i+=2)
-           fputc(c[i],stderr);
+#define ADD_CHAR(c) {buffer[j] = (c); if (buffer[j] < ' ') buffer[j] = '°'; j++;}
+           ADD_CHAR(c[i]);
        for(i=14;i<26 && c[i] && c[i]!=0xff;i+=2)
-           fputc(c[i],stderr);
+           ADD_CHAR(c[i]);
        for(i=28;i<32 && c[i] && c[i]!=0xff;i+=2)
-           fputc(c[i],stderr);
-       fputc('\n',stderr);
+           ADD_CHAR(c[i]);
+       buffer[j] = 0;
+       fprintf(stderr, "%s\n", buffer);
     } else {
        int i;
        for(i=0;i<11;i++)
-           fputc(direntry->name[i],stderr);
-       fprintf(stderr,"attributes=0x%02x begin=%d size=%d\n",
+           ADD_CHAR(direntry->name[i]);
+       buffer[j] = 0;
+       fprintf(stderr,"%s attributes=0x%02x begin=%d size=%d\n",
+               buffer,
                direntry->attributes,
-               direntry->begin,direntry->size);
+               begin_of_direntry(direntry),le32_to_cpu(direntry->size));
     }
 }
 
-static void print_changed_sector(BlockDriverState *bs,int64_t sector_num,const uint8_t *buf)
+static void print_mapping(const mapping_t* mapping)
 {
-    BDRVVVFATState *s = bs->opaque;
-
-    if(sector_num<s->first_sectors_number)
-       return;
-    if(sector_num<s->first_sectors_number+s->sectors_per_fat*2) {
-       int first=((sector_num-s->first_sectors_number)%s->sectors_per_fat);
-       int first_fat_entry=first*0x200/2;
-       int i;
-
-       fprintf(stderr, "fat:\n");
-       for(i=0;i<0x200;i+=2) {
-           uint16_t* f=array_get(&(s->fat),first_fat_entry+i/2);
-           if(memcmp(buf+i,f,2))
-               fprintf(stderr,"%d(%d->%d) ",first_fat_entry+i/2,*f,*(uint16_t*)(buf+i));
-       }
-       fprintf(stderr, "\n");
-    } else if(sector_num<s->faked_sectors) {
-       direntry_t* d=(direntry_t*)buf;
-       int i;
-       fprintf(stderr, "directory:\n");
-       for(i=0;i<0x200/sizeof(direntry_t);i++) {
-           direntry_t* d_old=(direntry_t*)(s->directory.pointer+0x200*(sector_num-s->first_sectors_number-s->sectors_per_fat*2)+i*sizeof(direntry_t));
-           if(memcmp(d+i,d_old,sizeof(direntry_t))) {
-               fprintf(stderr, "old: "); print_direntry(d_old);
-               fprintf(stderr, "new: "); print_direntry(d+i);
-               fprintf(stderr, "\n");
-           }
-       }
-    } else {
-       int sec=(sector_num-s->first_sectors_number-2*s->sectors_per_fat);
-       fprintf(stderr, "\tcluster: %d(+%d sectors)\n",sec/s->sectors_per_cluster,sec%s->sectors_per_cluster);
-    }
+    fprintf(stderr, "mapping (0x%x): begin, end = %d, %d, dir_index = %d, first_mapping_index = %d, name = %s, mode = 0x%x, " , (int)mapping, mapping->begin, mapping->end, mapping->dir_index, mapping->first_mapping_index, mapping->path, mapping->mode);
+    if (mapping->mode & MODE_DIRECTORY)
+       fprintf(stderr, "parent_mapping_index = %d, first_dir_index = %d\n", mapping->info.dir.parent_mapping_index, mapping->info.dir.first_dir_index);
+    else
+       fprintf(stderr, "offset = %d\n", mapping->info.file.offset);
 }
+#endif
 
-char direntry_is_free(const direntry_t* direntry)
+static int vvfat_read(BlockDriverState *bs, int64_t sector_num, 
+                    uint8_t *buf, int nb_sectors)
 {
-    return direntry->name[0]==0 || direntry->name[0]==0xe5;
-}
-
-/* TODO: use this everywhere */
-static inline uint32_t begin_of_direntry(direntry_t* direntry)
-{
-    return le16_to_cpu(direntry->begin)|(le16_to_cpu(direntry->begin_hi)<<16);
-}
-
-int consistency_check1(BDRVVVFATState *s) {
-    /* check all mappings */
+    BDRVVVFATState *s = bs->opaque;
     int i;
-    for(i=0;i<s->mapping.next;i++) {
-       mapping_t* mapping=array_get(&(s->mapping),i);
-       int j;
-       for(j=mapping->begin;j<mapping->end-1;j++)
-           assert(fat_get(s,j)==j+1);
-       assert(fat_get(s,j)==(0x7fffffff&s->max_fat_value));
-    }
-    return 0;
-}
 
-int consistency_check2(BDRVVVFATState *s) {
-    /* check fat entries: consecutive fat entries should be mapped in one mapping */
-    int i;
-    /* TODO: i=0 (mappings for direntries have to be sorted) */
-    for(i=s->sectors_for_directory/s->sectors_per_cluster;i<s->fat.next-1;i++) {
-       uint32_t j=fat_get(s,i);
-       if(j!=i+1 && j!=0 && !fat_eof(s,j)) {
-           mapping_t* mapping=find_mapping_for_cluster(s,i+1);
-           assert(mapping->begin==i+1);
+    for(i=0;i<nb_sectors;i++,sector_num++) {
+       if (sector_num >= s->sector_count)
+          return -1;
+       if (s->qcow) {
+           int n;
+           if (s->qcow->drv->bdrv_is_allocated(s->qcow,
+                       sector_num, nb_sectors-i, &n)) {
+DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
+               if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
+                   return -1;
+               i += n - 1;
+               sector_num += n - 1;
+               continue;
+           }
+DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
        }
-    }
-    return 0;
-}
-
-int consistency_check3(BDRVVVFATState *s) {
-    /* check that for each file there is exactly one mapping per cluster */
-    int i,count_non_next=0;
-    for(i=0;i<s->mapping.next;i++) {
-       mapping_t* mapping=array_get(&(s->mapping),i);
-       /* TODO: when directories are correctly adapted, add them here */
-       assert(mapping->begin<mapping->end);
-       if(mapping->mode==MODE_NORMAL) {
-           int j,count=0,count_next=0;
-           for(j=0;j<s->mapping.next;j++) {
-               mapping_t* other=array_get(&(s->mapping),j);
-               if(mapping->begin<other->end&&mapping->end>other->begin)
-                   count++;
-               if(mapping->end==other->begin)
-                   count_next++;
+       if(sector_num<s->faked_sectors) {
+           if(sector_num<s->first_sectors_number)
+               memcpy(buf+i*0x200,&(s->first_sectors[sector_num*0x200]),0x200);
+           else if(sector_num-s->first_sectors_number<s->sectors_per_fat)
+               memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number)*0x200]),0x200);
+           else if(sector_num-s->first_sectors_number-s->sectors_per_fat<s->sectors_per_fat)
+               memcpy(buf+i*0x200,&(s->fat.pointer[(sector_num-s->first_sectors_number-s->sectors_per_fat)*0x200]),0x200);
+       } else {
+           uint32_t sector=sector_num-s->faked_sectors,
+           sector_offset_in_cluster=(sector%s->sectors_per_cluster),
+           cluster_num=sector/s->sectors_per_cluster;
+           if(read_cluster(s, cluster_num) != 0) {
+               /* LATER TODO: strict: return -1; */
+               memset(buf+i*0x200,0,0x200);
+               continue;
            }
-           assert(count==1); /* no overlapping mappings */
-           assert(count_next==1 || count_next==0); /* every mapping except the last one has a successor */
-           if(!count_next)
-               count_non_next++;
+           memcpy(buf+i*0x200,s->cluster+sector_offset_in_cluster*0x200,0x200);
        }
     }
-    assert(count_non_next==1); /* only one last mapping */
     return 0;
 }
 
-static inline commit_t* commit_get_next(BDRVVVFATState* s)
-{
-    commit_t* commit=array_get_next(&(s->commit));
-    if((commit->buf=malloc(s->cluster_size))==0) {
-       /* out of memory */
-       s->commit.next--;
-       return 0;
-    }
-    return commit;
-}
+/* LATER TODO: statify all functions */
 
-int commit_remove(BDRVVVFATState* s,commit_t* commit)
-{
-    int index=commit-(commit_t*)s->commit.pointer;
-    free(commit->buf);
-    if(array_roll(&(s->commit),s->commit.next-1,index,1))
-       return -1;
-    s->commit.next--;
-    return 0;
-}
-
-/* TODO: the plan for write support:
- *
- * it seems that the direntries are written first, then the data is committed
- * to the free sectors, then fat 1 is updated, then fat2.
- *
- * Plan: when sectors are written, do the following:
- *
- * - if they are in a directory, check if the entry has changed. if yes,
- *   look what has changed (different strategies for name, begin & size).
- *
- *   if it is new (old entry is only 0's or has E5 at the start), create it,
- *   and also create mapping, but in a special mode "undefined" (TODO),
- *   because we cannot know which clusters belong to it yet.
+/*
+ * Idea of the write support (use snapshot):
  *
- *   if it is zeroed, or has E5 at the start, look if has just moved. If yes,
- *   copy the entry to the new position. If no, delete the file.
+ * 1. check if all data is consistent, recording renames, modifications,
+ *    new files and directories (in s->commits).
  *
- * - if they are in data, and the cluster is undefined, add it to the commit
- *   list. if the cluster is defined (find_mapping), then write it into the
- *   corresponding file.
+ * 2. if the data is not consistent, stop committing
  *
- *   If it is the last cluster (TODO: add a function
- *   fat_get(s,cluster); ), make sure not to write a complete cluster_size.
+ * 3. handle renames, and create new files and directories (do not yet
+ *    write their contents)
  *
- *   If the data is in current_cluster, update s->cluster.
+ * 4. walk the directories, fixing the mapping and direntries, and marking
+ *    the handled mappings as not deleted
  *
- * - if they are in fat 1, update mappings, look in the commit list
- *   (assertions!) and if the cluster is now known (or changed from undefined
- *   state to defined state, like when begin or size changed in a direntry),
- *   write it.
+ * 5. commit the contents of the files
  *
- * - if they are in fat 2, make sure they match with current fat.
+ * 6. handle deleted files and directories
  *
  */
 
-void mapping_modify_from_direntry(BDRVVVFATState* s,mapping_t* mapping,direntry_t* direntry)
-{
-    int begin=le16_to_cpu(direntry->begin),
-        end=begin+le32_to_cpu(direntry->size)/s->cluster_size+1,
-       i;
-    mapping->mode = MODE_MODIFIED;
-    /* TODO: what if begin==0 (size==0)? */
-    mapping->begin = begin;
-    /* TODO: why not just mapping->end = begin+1 ? */
-    for(i=begin+1;i<end && (fat_get(s,i)==0 || fat_get(s,i)==i+1);i++);
-    mapping->end = i;
-}
+typedef struct commit_t {
+    char* path;
+    union {
+       struct { uint32_t cluster; } rename;
+       struct { int dir_index; uint32_t modified_offset; } writeout;
+       struct { uint32_t first_cluster; } new_file;
+       struct { uint32_t cluster; } mkdir;
+    } param;
+    /* DELETEs and RMDIRs are handled differently: see handle_deletes() */
+    enum {
+       ACTION_RENAME, ACTION_WRITEOUT, ACTION_NEW_FILE, ACTION_MKDIR
+    } action;
+} commit_t;
 
-mapping_t* find_mapping_for_direntry(BDRVVVFATState* s,direntry_t* direntry)
+static void clear_commits(BDRVVVFATState* s)
 {
     int i;
-    int dir_index=direntry-((direntry_t*)s->directory.pointer);
-    
-    /* TODO: support allocation for new clusters for directories (new/larger directory */
-    assert(dir_index<0x200/0x20*s->sectors_for_directory);
-    
-    for(i=0;i<s->mapping.next;i++) {
-       mapping_t* mapping=array_get(&(s->mapping),i);
-       if(mapping->dir_index==dir_index && mapping->offset==0 &&
-               mapping->mode!=MODE_UNDEFINED)
-           return mapping;
+DLOG(fprintf(stderr, "clear_commits (%d commits)\n", s->commits.next));
+    for (i = 0; i < s->commits.next; i++) {
+       commit_t* commit = array_get(&(s->commits), i);
+       assert(commit->path || commit->action == ACTION_WRITEOUT);
+       if (commit->action != ACTION_WRITEOUT) {
+           assert(commit->path);
+           free(commit->path);
+       } else
+           assert(commit->path == NULL);
     }
-    return 0;
+    s->commits.next = 0;
 }
 
-static inline uint32_t sector2cluster(BDRVVVFATState* s,off_t sector_num)
+static void schedule_rename(BDRVVVFATState* s,
+       uint32_t cluster, char* new_path)
 {
-    return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)/s->sectors_per_cluster;
+    commit_t* commit = array_get_next(&(s->commits));
+    commit->path = new_path;
+    commit->param.rename.cluster = cluster;
+    commit->action = ACTION_RENAME;
 }
 
-static inline uint32_t sector_offset_in_cluster(BDRVVVFATState* s,off_t sector_num)
+static void schedule_writeout(BDRVVVFATState* s,
+       int dir_index, uint32_t modified_offset)
 {
-    return (sector_num-s->first_sectors_number-2*s->sectors_per_fat)%s->sectors_per_cluster;
+    commit_t* commit = array_get_next(&(s->commits));
+    commit->path = NULL;
+    commit->param.writeout.dir_index = dir_index;
+    commit->param.writeout.modified_offset = modified_offset;
+    commit->action = ACTION_WRITEOUT;
 }
 
-static commit_t* get_commit_for_cluster(BDRVVVFATState* s,uint32_t cluster_num)
+static void schedule_new_file(BDRVVVFATState* s,
+       char* path, uint32_t first_cluster)
 {
-    int i;
-    for(i=0;i<s->commit.next;i++) {
-       commit_t* commit=array_get(&(s->commit),i);
-       if(commit->cluster_num==cluster_num)
-           return commit;
+    commit_t* commit = array_get_next(&(s->commits));
+    commit->path = path;
+    commit->param.new_file.first_cluster = first_cluster;
+    commit->action = ACTION_NEW_FILE;
+}
+
+static void schedule_mkdir(BDRVVVFATState* s, uint32_t cluster, char* path)
+{
+    commit_t* commit = array_get_next(&(s->commits));
+    commit->path = path;
+    commit->param.mkdir.cluster = cluster;
+    commit->action = ACTION_MKDIR;
+}
+
+typedef struct {
+    unsigned char name[1024];
+    int checksum, len;
+    int sequence_number;
+} long_file_name;
+
+static void lfn_init(long_file_name* lfn)
+{
+   lfn->sequence_number = lfn->len = 0;
+   lfn->checksum = 0x100;
+}
+
+/* return 0 if parsed successfully, > 0 if no long name, < 0 if error */
+static int parse_long_name(long_file_name* lfn,
+       const direntry_t* direntry)
+{
+    int i, j, offset;
+    const unsigned char* pointer = (const unsigned char*)direntry;
+
+    if (!is_long_name(direntry))
+       return 1;
+
+    if (pointer[0] & 0x40) {
+       lfn->sequence_number = pointer[0] & 0x3f;
+       lfn->checksum = pointer[13];
+       lfn->name[0] = 0;
+    } else if ((pointer[0] & 0x3f) != --lfn->sequence_number)
+       return -1;
+    else if (pointer[13] != lfn->checksum)
+       return -2;
+    else if (pointer[12] || pointer[26] || pointer[27])
+       return -3;
+
+    offset = 13 * (lfn->sequence_number - 1);
+    for (i = 0, j = 1; i < 13; i++, j+=2) {
+       if (j == 11)
+           j = 14;
+       else if (j == 26)
+           j = 28;
+
+       if (pointer[j+1] == 0)
+           lfn->name[offset + i] = pointer[j];
+       else if (pointer[j+1] != 0xff || (pointer[0] & 0x40) == 0)
+           return -4;
+       else
+           lfn->name[offset + i] = 0;
     }
+
+    if (pointer[0] & 0x40)
+       lfn->len = offset + strlen(lfn->name + offset);
+
     return 0;
 }
 
-static inline commit_t* create_or_get_commit_for_sector(BDRVVVFATState* s,off_t sector_num)
+/* returns 0 if successful, >0 if no short_name, and <0 on error */
+static int parse_short_name(BDRVVVFATState* s,
+       long_file_name* lfn, direntry_t* direntry)
 {
-    int i;
-    commit_t* commit;
-    uint32_t cluster_num=sector2cluster(s,sector_num);
+    int i, j;
+
+    if (!is_short_name(direntry))
+       return 1;
 
-    for(i=0;i<s->commit.next;i++) {
-       commit=array_get(&(s->commit),i);
-       if(commit->cluster_num==cluster_num)
-           return commit;
+    for (j = 7; j >= 0 && direntry->name[j] == ' '; j--);
+    for (i = 0; i <= j; i++) {
+       if (direntry->name[i] <= ' ' || direntry->name[i] > 0x7f)
+           return -1;
+       else if (s->downcase_short_names)
+           lfn->name[i] = tolower(direntry->name[i]);
+       else
+           lfn->name[i] = direntry->name[i];
     }
 
-    commit=commit_get_next(s);
-    commit->cluster_num=cluster_num;
-    /* we can ignore read errors here */
-    read_cluster(s,cluster_num);
-    memcpy(commit->buf,s->cluster,s->cluster_size);
-    return commit;
+    for (j = 2; j >= 0 && direntry->extension[j] == ' '; j--);
+    if (j >= 0) {
+       lfn->name[i++] = '.';
+       lfn->name[i + j + 1] = '\0';
+       for (;j >= 0; j--) {
+           if (direntry->extension[j] <= ' ' || direntry->extension[j] > 0x7f)
+               return -2;
+           else if (s->downcase_short_names)
+               lfn->name[i + j] = tolower(direntry->extension[j]);
+           else
+               lfn->name[i + j] = direntry->extension[j];
+       }
+    } else
+       lfn->name[i + j + 1] = '\0';
+
+    lfn->len = strlen(lfn->name);
+
+    return 0;
 }
 
-static direntry_t* get_direntry_for_mapping(BDRVVVFATState* s,mapping_t* mapping)
+static inline uint32_t modified_fat_get(BDRVVVFATState* s,
+       unsigned int cluster)
 {
-    if(mapping->mode==MODE_UNDEFINED)
-       return 0;
-    if(mapping->dir_index>=0x200/0x20*s->sectors_for_directory)
+    if (cluster < s->last_cluster_of_root_directory) {
+       if (cluster + 1 == s->last_cluster_of_root_directory)
+           return s->max_fat_value;
+       else
+           return cluster + 1;
+    }
+
+    if (s->fat_type==32) {
+        uint32_t* entry=((uint32_t*)s->fat2)+cluster;
+        return le32_to_cpu(*entry);
+    } else if (s->fat_type==16) {
+        uint16_t* entry=((uint16_t*)s->fat2)+cluster;
+        return le16_to_cpu(*entry);
+    } else {
+        const uint8_t* x=s->fat2+cluster*3/2;
+        return ((x[0]|(x[1]<<8))>>(cluster&1?4:0))&0x0fff;
+    }
+}
+
+static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
+{
+    int was_modified = 0;
+    int i, dummy;
+
+    if (s->qcow == NULL)
        return 0;
-    return (direntry_t*)(s->directory.pointer+sizeof(direntry_t)*mapping->dir_index);
+
+    for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
+       was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
+               cluster2sector(s, cluster_num) + i, 1, &dummy);
+
+    return was_modified;
 }
 
-static void print_mappings(BDRVVVFATState* s)
+static const char* get_basename(const char* path)
 {
-    int i;
-    fprintf(stderr,"mapping:\n");
-    for(i=0;i<s->mapping.next;i++) {
-       mapping_t* m=array_get(&(s->mapping),i);
-       direntry_t* d=get_direntry_for_mapping(s,m);
-       fprintf(stderr,"%02d %d-%d (%d) %s (dir: %d)",i,(int)m->begin,(int)m->end,(int)m->offset,m->filename,m->dir_index);
-       print_direntry(d);
-       fprintf(stderr,"\n");
-    }
-    fprintf(stderr,"mappings end.\n");
+    char* basename = strrchr(path, '/');
+    if (basename == NULL)
+       return path;
+    else
+       return basename + 1; /* strip '/' */
 }
 
-/* TODO: statify all functions */
+/*
+ * The array s->used_clusters holds the states of the clusters. If it is
+ * part of a file, it has bit 2 set, in case of a directory, bit 1. If it
+ * was modified, bit 3 is set.
+ * If any cluster is allocated, but not part of a file or directory, this
+ * driver refuses to commit.
+ */
+typedef enum {
+     USED_DIRECTORY = 1, USED_FILE = 2, USED_ANY = 3, USED_ALLOCATED = 4
+} used_t;
 
-/* This function is only meant for file contents.
- * It will return an error if used for other sectors. */
-static int write_cluster(BDRVVVFATState* s,uint32_t cluster_num,const uint8_t* buf)
+/*
+ * get_cluster_count_for_direntry() not only determines how many clusters
+ * are occupied by direntry, but also if it was renamed or modified.
+ *
+ * A file is thought to be renamed *only* if there already was a file with
+ * exactly the same first cluster, but a different name.
+ *
+ * Further, the files/directories handled by this function are
+ * assumed to be *not* deleted (and *only* those).
+ */
+static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
+       direntry_t* direntry, const char* path)
 {
-    /* sector_offset is the sector_num relative to the first cluster */
-    mapping_t* mapping=find_mapping_for_cluster(s,cluster_num);
-    direntry_t* direntry;
-    int next_cluster,write_size,last_cluster;
-    off_t offset;
+    /*
+     * This is a little bit tricky:
+     * IF the guest OS just inserts a cluster into the file chain,
+     * and leaves the rest alone, (i.e. the original file had clusters
+     * 15 -> 16, but now has 15 -> 32 -> 16), then the following happens:
+     *
+     * - do_commit will write the cluster into the file at the given
+     *   offset, but
+     *
+     * - the cluster which is overwritten should be moved to a later
+     *   position in the file.
+     *
+     * I am not aware that any OS does something as braindead, but this
+     * situation could happen anyway when not committing for a long time.
+     * Just to be sure that this does not bite us, detect it, and copy the
+     * contents of the clusters to-be-overwritten into the qcow.
+     */
+    int copy_it = 0;
+    int was_modified = 0;
+    int32_t ret = 0;
+
+    uint32_t cluster_num = begin_of_direntry(direntry);
+    uint32_t offset = 0;
+    int first_mapping_index = -1;
+    mapping_t* mapping = NULL;
+    const char* basename2 = NULL;
 
-    /* if this cluster is free, return error */
-    next_cluster=fat_get(s,cluster_num);
-    if(next_cluster<2)
-       return -1;
-    
-    /* TODO: MODE_DIRECTORY */
-    if(!mapping || mapping->mode==MODE_UNDEFINED || mapping->mode==MODE_DIRECTORY)
-       return -1;
-    direntry=get_direntry_for_mapping(s,mapping);
-    if(!direntry)
-       return -2;
+    vvfat_close_current_file(s);
 
-    /* get size to write */
-    last_cluster=fat_eof(s,next_cluster);
-    write_size=!last_cluster?s->cluster_size:
-       (le32_to_cpu(direntry->size)%s->cluster_size);
-    if(write_size<=0)
+    /* the root directory */
+    if (cluster_num == 0)
        return 0;
-    //fprintf(stderr,"next_cluster: %d (%d), write_size: %d, %d, %d\n",next_cluster,s->max_fat_value-8,write_size,direntry->size,s->cluster_size);
 
-    if(open_file(s,mapping,O_RDWR))
-       return -4;
-   
-    offset=(cluster_num-mapping->begin+mapping->offset)*s->cluster_size;
-    if(lseek(s->current_fd,offset,SEEK_SET)!=offset)
-       return -3;
-    if(write(s->current_fd,buf,write_size)!=write_size) {
-       lseek(s->current_fd,0,SEEK_END);
-       vvfat_close_current_file(s);
-       return -2;
-    }
+    /* write support */
+    if (s->qcow) {
+       basename2 = get_basename(path);
 
-    /* seek to end of file, so it doesn't get truncated */
-    if(!last_cluster)
-       lseek(s->current_fd,0,SEEK_END);
-    else {
-       ftruncate(s->current_fd,le32_to_cpu(direntry->size));
-       vvfat_close_current_file(s);
+       mapping = find_mapping_for_cluster(s, cluster_num);
+
+       if (mapping) {
+           assert(mapping->mode & MODE_DELETED);
+           mapping->mode &= ~MODE_DELETED;
+
+           const char* basename = get_basename(mapping->path);
+
+           assert(mapping->mode & MODE_NORMAL);
+
+           /* rename */
+           if (strcmp(basename, basename2))
+               schedule_rename(s, cluster_num, strdup(path));
+       } else if (is_file(direntry))
+           /* new file */
+           schedule_new_file(s, strdup(path), cluster_num);
+       else {
+           assert(0);
+           return 0;
+       }
     }
 
-    /* update s->cluster if necessary */
-    if(cluster_num==s->current_cluster && s->cluster!=buf)
-       memcpy(s->cluster,buf,s->cluster_size);
+    while(1) {
+       if (s->qcow) {
+           if (!copy_it && cluster_was_modified(s, cluster_num)) {
+               if (mapping == NULL ||
+                       mapping->begin > cluster_num ||
+                       mapping->end <= cluster_num)
+               mapping = find_mapping_for_cluster(s, cluster_num);
 
-    return 0;
+
+               if (mapping &&
+                       (mapping->mode & MODE_DIRECTORY) == 0) {
+
+                   /* was modified in qcow */
+                   if (offset != mapping->info.file.offset + s->cluster_size
+                           * (cluster_num - mapping->begin)) {
+                       /* offset of this cluster in file chain has changed */
+                       assert(0);
+                       copy_it = 1;
+                   } else if (offset == 0) {
+                       const char* basename = get_basename(mapping->path);
+
+                       if (strcmp(basename, basename2))
+                           copy_it = 1;
+                       first_mapping_index = array_index(&(s->mapping), mapping);
+                   }
+
+                   if (mapping->first_mapping_index != first_mapping_index
+                           && mapping->info.file.offset > 0) {
+                       assert(0);
+                       copy_it = 1;
+                   }
+
+                   /* need to write out? */
+                   if (!was_modified && is_file(direntry)) {
+                       was_modified = 1;
+                       schedule_writeout(s, mapping->dir_index, offset);
+                   }
+               }
+           }
+
+           if (copy_it) {
+               int i, dummy;
+               /*
+                * This is horribly inefficient, but that is okay, since
+                * it is rarely executed, if at all.
+                */
+               int64_t offset = cluster2sector(s, cluster_num);
+
+               vvfat_close_current_file(s);
+               for (i = 0; i < s->sectors_per_cluster; i++)
+                   if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
+                               offset + i, 1, &dummy)) {
+                       if (vvfat_read(s->bs,
+                                   offset, s->cluster_buffer, 1))
+                           return -1;
+                       if (s->qcow->drv->bdrv_write(s->qcow,
+                                   offset, s->cluster_buffer, 1))
+                           return -2;
+                   }
+           }
+       }
+
+       ret++;
+       if (s->used_clusters[cluster_num] & USED_ANY)
+           return 0;
+       s->used_clusters[cluster_num] = USED_FILE;
+
+       cluster_num = modified_fat_get(s, cluster_num);
+
+       if (fat_eof(s, cluster_num))
+           return ret;
+       else if (cluster_num < 2 || cluster_num > s->max_fat_value - 16)
+           return -1;
+
+       offset += s->cluster_size;
+    }
 }
 
-/* this function returns !=0 on error */
-int mapping_is_consistent(BDRVVVFATState* s,mapping_t* mapping)
+/*
+ * 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.
+ */
+static int check_directory_consistency(BDRVVVFATState *s,
+       int cluster_num, const char* path)
 {
-    direntry_t* direntry=get_direntry_for_mapping(s,mapping);
-    uint32_t cluster_count=0;
-    int commit_count=0; /* number of commits for this file (we also write incomplete files; think "append") */
-    //fprintf(stderr,"check direntry for %s\n",mapping->filename);
-    while(mapping) {
+    int ret = 0;
+    unsigned char* cluster = malloc(s->cluster_size);
+    direntry_t* direntries = (direntry_t*)cluster;
+    mapping_t* mapping = find_mapping_for_cluster(s, cluster_num);
+
+    long_file_name lfn;
+    int path_len = strlen(path);
+    char path2[PATH_MAX];
+
+    assert(path_len < PATH_MAX); /* len was tested before! */
+    strcpy(path2, path);
+    path2[path_len] = '/';
+    path2[path_len + 1] = '\0';
+
+    if (mapping) {
+       const char* basename = get_basename(mapping->path);
+       const char* basename2 = get_basename(path);
+
+       assert(mapping->mode & MODE_DIRECTORY);
+
+       assert(mapping->mode & MODE_DELETED);
+       mapping->mode &= ~MODE_DELETED;
+
+       if (strcmp(basename, basename2))
+           schedule_rename(s, cluster_num, strdup(path));
+    } else
+       /* new directory */
+       schedule_mkdir(s, cluster_num, strdup(path));
+               
+    lfn_init(&lfn);
+    do {
        int i;
-       assert(mapping->begin<mapping->end);
-       for(i=mapping->begin;i<mapping->end-1;i++) {
-           if(i<=0 || fat_get(s,i)!=i+1) {
-               /*fprintf(stderr,"the fat mapping of %d is not %d, but %d\n",
-                       i,i+1,fat_get(s,i));*/
-               return -1;
+       int subret = 0;
+
+       ret++;
+
+       if (s->used_clusters[cluster_num] & USED_ANY) {
+           fprintf(stderr, "cluster %d used more than once\n", (int)cluster_num);
+           return 0;
+       }
+       s->used_clusters[cluster_num] = USED_DIRECTORY;
+
+DLOG(fprintf(stderr, "read cluster %d (sector %d)\n", (int)cluster_num, (int)cluster2sector(s, cluster_num)));
+       subret = vvfat_read(s->bs, cluster2sector(s, cluster_num), cluster,
+               s->sectors_per_cluster);
+       if (subret) {
+           fprintf(stderr, "Error fetching direntries\n");
+       fail:
+           free(cluster);
+           return 0;
+       }
+
+       for (i = 0; i < 0x10 * s->sectors_per_cluster; i++) {
+           int cluster_count;
+
+DLOG(fprintf(stderr, "check direntry %d: \n", i); print_direntry(direntries + i));
+           if (is_volume_label(direntries + i) || is_dot(direntries + i) ||
+                   is_free(direntries + i))
+               continue;
+
+           subret = parse_long_name(&lfn, direntries + i);
+           if (subret < 0) {
+               fprintf(stderr, "Error in long name\n");
+               goto fail;
+           }
+           if (subret == 0 || is_free(direntries + i))
+               continue;
+
+           if (fat_chksum(direntries+i) != lfn.checksum) {
+               subret = parse_short_name(s, &lfn, direntries + i);
+               if (subret < 0) {
+                   fprintf(stderr, "Error in short name (%d)\n", subret);
+                   goto fail;
+               }
+               if (subret > 0 || !strcmp(lfn.name, ".")
+                       || !strcmp(lfn.name, ".."))
+                   continue;
+           }
+           lfn.checksum = 0x100; /* cannot use long name twice */
+
+           if (path_len + 1 + lfn.len >= PATH_MAX) {
+               fprintf(stderr, "Name too long: %s/%s\n", path, lfn.name);
+               goto fail;
            }
-           if(get_commit_for_cluster(s,i))
-               commit_count++;
+           strcpy(path2 + path_len + 1, lfn.name);
+
+           if (is_directory(direntries + i)) {
+               if (begin_of_direntry(direntries + i) == 0) {
+                   DLOG(fprintf(stderr, "invalid begin for directory: %s\n", path2); print_direntry(direntries + i));
+                   goto fail;
+               }
+               cluster_count = check_directory_consistency(s,
+                       begin_of_direntry(direntries + i), path2);
+               if (cluster_count == 0) {
+                   DLOG(fprintf(stderr, "problem in directory %s:\n", path2); print_direntry(direntries + i));
+                   goto fail;
+               }
+           } else if (is_file(direntries + i)) {
+               /* check file size with FAT */
+               cluster_count = get_cluster_count_for_direntry(s, direntries + i, path2);
+               if (cluster_count !=
+                       (le32_to_cpu(direntries[i].size) + s->cluster_size
+                        - 1) / s->cluster_size) {
+                   DLOG(fprintf(stderr, "Cluster count mismatch\n"));
+                   goto fail;
+               }
+           } else
+               assert(0); /* cluster_count = 0; */
+
+           ret += cluster_count;
        }
-       if(get_commit_for_cluster(s,i))
-           commit_count++;
 
-       cluster_count+=mapping->end-mapping->begin;
-       
-       i=fat_get(s,mapping->end-1);
-       if(fat_eof(s,i))
-           break;
+       cluster_num = modified_fat_get(s, cluster_num);
+    } while(!fat_eof(s, cluster_num));
 
-       mapping=find_mapping_for_cluster(s,i);
-       if(!mapping) {
-           //fprintf(stderr,"No mapping found for %d\n",i);
-           print_mappings(s);
-           return -2;
+    free(cluster);
+    return ret;
+}
+
+/* returns 1 on success */
+static int is_consistent(BDRVVVFATState* s)
+{
+    int i, check;
+    int used_clusters_count = 0;
+
+DLOG(checkpoint());
+    /*
+     * - get modified FAT
+     * - compare the two FATs (TODO)
+     * - get buffer for marking used clusters
+     * - recurse direntries from root (using bs->bdrv_read to make
+     *    sure to get the new data)
+     *   - check that the FAT agrees with the size
+     *   - count the number of clusters occupied by this directory and
+     *     its files
+     * - check that the cumulative used cluster count agrees with the
+     *   FAT
+     * - if all is fine, return number of used clusters
+     */
+    if (s->fat2 == NULL) {
+       int size = 0x200 * s->sectors_per_fat;
+       s->fat2 = malloc(size);
+       memcpy(s->fat2, s->fat.pointer, size);
+    }
+    check = vvfat_read(s->bs,
+           s->first_sectors_number, s->fat2, s->sectors_per_fat);
+    if (check) {
+       fprintf(stderr, "Could not copy fat\n");
+       return 0;
+    }
+    assert (s->used_clusters);
+    for (i = 0; i < sector2cluster(s, s->sector_count); i++)
+       s->used_clusters[i] &= ~USED_ANY;
+
+    clear_commits(s);
+
+    /* mark every mapped file/directory as deleted.
+     * (check_directory_consistency() will unmark those still present). */
+    if (s->qcow)
+       for (i = 0; i < s->mapping.next; i++) {
+           mapping_t* mapping = array_get(&(s->mapping), i);
+           if (mapping->first_mapping_index < 0)
+               mapping->mode |= MODE_DELETED;
        }
+
+    used_clusters_count = check_directory_consistency(s, 0, s->path);
+    if (used_clusters_count <= 0) {
+       DLOG(fprintf(stderr, "problem in directory\n"));
+       return 0;
     }
 
-    if(cluster_count!=(le32_to_cpu(direntry->size)+s->cluster_size-1)/s->cluster_size) {
-       //fprintf(stderr,"cluster_count is %d, but size is %d\n",cluster_count,le32_to_cpu(direntry->size));
-       return -3;
+    check = s->last_cluster_of_root_directory;
+    for (i = check; i < sector2cluster(s, s->sector_count); i++) {
+       if (modified_fat_get(s, i)) {
+           if(!s->used_clusters[i]) {
+               DLOG(fprintf(stderr, "FAT was modified (%d), but cluster is not used?\n", i));
+               return 0;
+           }
+           check++;
+       }
+
+       if (s->used_clusters[i] == USED_ALLOCATED) {
+           /* allocated, but not used... */
+           DLOG(fprintf(stderr, "unused, modified cluster: %d\n", i));
+           return 0;
+       }
     }
 
-    if(commit_count==0)
-       return -4;
+    if (check != used_clusters_count)
+       return 0;
+
+    return used_clusters_count;
+}
+
+static inline void adjust_mapping_indices(BDRVVVFATState* s,
+       int offset, int adjust)
+{
+    int i;
+
+    for (i = 0; i < s->mapping.next; i++) {
+       mapping_t* mapping = array_get(&(s->mapping), i);
+
+#define ADJUST_MAPPING_INDEX(name) \
+       if (mapping->name >= offset) \
+           mapping->name += adjust
+
+       ADJUST_MAPPING_INDEX(first_mapping_index);
+       if (mapping->mode & MODE_DIRECTORY)
+           ADJUST_MAPPING_INDEX(info.dir.parent_mapping_index);
+    }
+}
+
+/* insert or update mapping */
+static mapping_t* insert_mapping(BDRVVVFATState* s,
+       uint32_t begin, uint32_t end)
+{
+    /*
+     * - find mapping where mapping->begin >= begin,
+     * - if mapping->begin > begin: insert
+     *   - adjust all references to mappings!
+     * - else: adjust
+     * - replace name
+     */
+    int index = find_mapping_for_cluster_aux(s, begin, 0, s->mapping.next);
+    mapping_t* mapping = NULL;
+    mapping_t* first_mapping = array_get(&(s->mapping), 0);
+
+    if (index < s->mapping.next && (mapping = array_get(&(s->mapping), index))
+           && mapping->begin < begin) {
+       mapping->end = begin;
+       index++;
+       mapping = array_get(&(s->mapping), index);
+    }
+    if (index >= s->mapping.next || mapping->begin > begin) {
+       mapping = array_insert(&(s->mapping), index, 1);
+       mapping->path = NULL;
+       adjust_mapping_indices(s, index, +1);
+    }
+
+    mapping->begin = begin;
+    mapping->end = end;
+
+DLOG(mapping_t* next_mapping;
+assert(index + 1 >= s->mapping.next ||
+((next_mapping = array_get(&(s->mapping), index + 1)) &&
+ next_mapping->begin >= end)));
+
+    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
+       s->current_mapping = array_get(&(s->mapping),
+               s->current_mapping - first_mapping);
+
+    return mapping;
+}
+
+static int remove_mapping(BDRVVVFATState* s, int mapping_index)
+{
+    mapping_t* mapping = array_get(&(s->mapping), mapping_index);
+    mapping_t* first_mapping = array_get(&(s->mapping), 0);
+
+    /* free mapping */
+    if (mapping->first_mapping_index < 0)
+       free(mapping->path);
+
+    /* remove from s->mapping */
+    array_remove(&(s->mapping), mapping_index);
+
+    /* adjust all references to mappings */
+    adjust_mapping_indices(s, mapping_index, -1);
+
+    if (s->current_mapping && first_mapping != (mapping_t*)s->mapping.pointer)
+       s->current_mapping = array_get(&(s->mapping),
+               s->current_mapping - first_mapping);
 
-    //fprintf(stderr,"okay\n");
     return 0;
 }
 
-/* TODO: remember what comes third, and what's first in this OS:
- * FAT, direntry or data.
- * If the last written sector is either last in cluster or sector_num+nb_sectors-1,
- *     - commit every cluster for this file if mapping_is_consistent()==0
- *     - if the last written sector is first_action, and last_action=third_action, clear commit
- */
+static void adjust_dirindices(BDRVVVFATState* s, int offset, int adjust)
+{
+    int i;
+    for (i = 0; i < s->mapping.next; i++) {
+       mapping_t* mapping = array_get(&(s->mapping), i);
+       if (mapping->dir_index >= offset)
+           mapping->dir_index += adjust;
+       if ((mapping->mode & MODE_DIRECTORY) &&
+               mapping->info.dir.first_dir_index >= offset)
+           mapping->info.dir.first_dir_index += adjust;
+    }
+}
 
-static int commit_cluster_aux(BDRVVVFATState* s,commit_t* commit)
+static direntry_t* insert_direntries(BDRVVVFATState* s,
+       int dir_index, int count)
 {
-    int result=write_cluster(s,commit->cluster_num,commit->buf);
+    /*
+     * make room in s->directory,
+     * adjust_dirindices
+     */
+    direntry_t* result = array_insert(&(s->directory), dir_index, count);
+    if (result == NULL)
+       return NULL;
+    adjust_dirindices(s, dir_index, count);
     return result;
 }
 
+static int remove_direntries(BDRVVVFATState* s, int dir_index, int count)
+{
+    int ret = array_remove_slice(&(s->directory), dir_index, count);
+    if (ret)
+       return ret;
+    adjust_dirindices(s, dir_index, -count);
+    return 0;
+}
+
+/*
+ * Adapt the mappings of the cluster chain starting at first cluster
+ * (i.e. if a file starts at first_cluster, the chain is followed according
+ * to the modified fat, and the corresponding entries in s->mapping are
+ * adjusted)
+ */
+static int commit_mappings(BDRVVVFATState* s,
+       uint32_t first_cluster, int dir_index)
+{
+    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
+    direntry_t* direntry = array_get(&(s->directory), dir_index);
+    uint32_t cluster = first_cluster;
+
+    vvfat_close_current_file(s);
+
+    assert(mapping);
+    assert(mapping->begin == first_cluster);
+    mapping->first_mapping_index = -1;
+    mapping->dir_index = dir_index;
+    mapping->mode = (dir_index <= 0 || is_directory(direntry)) ?
+       MODE_DIRECTORY : MODE_NORMAL;
+
+    while (!fat_eof(s, cluster)) {
+       uint32_t c, c1;
+
+       for (c = cluster, c1 = modified_fat_get(s, c); c + 1 == c1;
+               c = c1, c1 = modified_fat_get(s, c1));
+
+       c++;
+       if (c > mapping->end) {
+           int index = array_index(&(s->mapping), mapping);
+           int i, max_i = s->mapping.next - index;
+           for (i = 1; i < max_i && mapping[i].begin < c; i++);
+           while (--i > 0)
+               remove_mapping(s, index + 1);
+       }
+       assert(mapping == array_get(&(s->mapping), s->mapping.next - 1)
+               || mapping[1].begin >= c);
+       mapping->end = c;
+
+       if (!fat_eof(s, c1)) {
+           int i = find_mapping_for_cluster_aux(s, c1, 0, s->mapping.next);
+           mapping_t* next_mapping = i >= s->mapping.next ? NULL :
+               array_get(&(s->mapping), i);
+
+           if (next_mapping == NULL || next_mapping->begin > c1) {
+               int i1 = array_index(&(s->mapping), mapping);
+
+               next_mapping = insert_mapping(s, c1, c1+1);
+
+               if (c1 < c)
+                   i1++;
+               mapping = array_get(&(s->mapping), i1);
+           }
 
-static int commit_cluster(BDRVVVFATState* s,uint32_t cluster_num)
+           next_mapping->dir_index = mapping->dir_index;
+           next_mapping->first_mapping_index = 
+               mapping->first_mapping_index < 0 ?
+               array_index(&(s->mapping), mapping) :
+               mapping->first_mapping_index;
+           next_mapping->path = mapping->path;
+           next_mapping->mode = mapping->mode;
+           next_mapping->read_only = mapping->read_only;
+           if (mapping->mode & MODE_DIRECTORY) {
+               next_mapping->info.dir.parent_mapping_index =
+                       mapping->info.dir.parent_mapping_index;
+               next_mapping->info.dir.first_dir_index =
+                       mapping->info.dir.first_dir_index +
+                       0x10 * s->sectors_per_cluster *
+                       (mapping->end - mapping->begin);
+           } else
+               next_mapping->info.file.offset = mapping->info.file.offset +
+                       mapping->end - mapping->begin;
+
+           mapping = next_mapping;
+       }
+               
+       cluster = c1;
+    }
+
+    return 0;
+}
+
+static int commit_direntries(BDRVVVFATState* s,
+       int dir_index, int parent_mapping_index)
 {
-    commit_t* commit;
+    direntry_t* direntry = array_get(&(s->directory), dir_index);
+    uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
+    mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
+
+    int factor = 0x10 * s->sectors_per_cluster;
+    int old_cluster_count, new_cluster_count;
+    int current_dir_index = mapping->info.dir.first_dir_index;
+    int first_dir_index = current_dir_index;
+    int ret, i;
+    uint32_t c;
+
+DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
+
+    assert(direntry);
+    assert(mapping);
+    assert(mapping->begin == first_cluster);
+    assert(mapping->info.dir.first_dir_index < s->directory.next);
+    assert(mapping->mode & MODE_DIRECTORY);
+    assert(dir_index == 0 || is_directory(direntry));
+
+    mapping->info.dir.parent_mapping_index = parent_mapping_index;
+
+    if (first_cluster == 0) {
+       old_cluster_count = new_cluster_count =
+           s->last_cluster_of_root_directory;
+    } else {
+       for (old_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
+               c = fat_get(s, c))
+           old_cluster_count++;
+
+       for (new_cluster_count = 0, c = first_cluster; !fat_eof(s, c);
+               c = modified_fat_get(s, c))
+           new_cluster_count++;
+    }
+
+    if (new_cluster_count > old_cluster_count) {
+       if (insert_direntries(s,
+               current_dir_index + factor * old_cluster_count,
+               factor * (new_cluster_count - old_cluster_count)) == NULL)
+           return -1;
+    } else if (new_cluster_count < old_cluster_count)
+       remove_direntries(s,
+               current_dir_index + factor * new_cluster_count,
+               factor * (old_cluster_count - new_cluster_count));
+
+    for (c = first_cluster; !fat_eof(s, c); c = modified_fat_get(s, c)) {
+       void* direntry = array_get(&(s->directory), current_dir_index);
+       int ret = vvfat_read(s->bs, cluster2sector(s, c), direntry,
+               s->sectors_per_cluster);
+       if (ret)
+           return ret;
+       assert(!strncmp(s->directory.pointer, "QEMU", 4));
+       current_dir_index += factor;
+    }
+
+    ret = commit_mappings(s, first_cluster, dir_index);
+    if (ret)
+       return ret;
+
+    /* recurse */
+    for (i = 0; i < factor * new_cluster_count; i++) {
+       direntry = array_get(&(s->directory), first_dir_index + i);
+       if (is_directory(direntry) && !is_dot(direntry)) {
+           mapping = find_mapping_for_cluster(s, first_cluster);
+           assert(mapping->mode & MODE_DIRECTORY);
+           ret = commit_direntries(s, first_dir_index + i,
+               array_index(&(s->mapping), mapping));
+           if (ret)
+               return ret;
+       }
+    }
 
-    /* commit the sectors of this cluster */
-    commit=get_commit_for_cluster(s,cluster_num);
-    if(commit)
-       return commit_cluster_aux(s,commit);
     return 0;
 }
 
-/* this function checks the consistency for the direntry which belongs to
- * the mapping. if everything is found consistent, the data is committed.
- * this returns 0 if no error occurred (even if inconsistencies were found) */
-static inline int commit_data_if_consistent(BDRVVVFATState* s,mapping_t* mapping,write_action_t action)
+/* commit one file (adjust contents, adjust mapping),
+   return first_mapping_index */
+static int commit_one_file(BDRVVVFATState* s,
+       int dir_index, uint32_t offset)
 {
-    direntry_t* direntry;
-    
-    if(!mapping)
-       return 0;
+    direntry_t* direntry = array_get(&(s->directory), dir_index);
+    uint32_t c = begin_of_direntry(direntry);
+    uint32_t first_cluster = c;
+    mapping_t* mapping = find_mapping_for_cluster(s, c);
+    uint32_t size = filesize_of_direntry(direntry);
+    char* cluster = malloc(s->cluster_size);
+    uint32_t i;
+    int fd = 0;
+
+    assert(offset < size);
+    assert((offset % s->cluster_size) == 0);
+
+    for (i = s->cluster_size; i < offset; i += s->cluster_size)
+       c = modified_fat_get(s, c);
+
+    fd = open(mapping->path, O_RDWR | O_CREAT, 0666);
+    if (fd < 0) {
+       fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
+               strerror(errno), errno);
+       return fd;
+    }
+    if (offset > 0)
+       if (lseek(fd, offset, SEEK_SET) != offset)
+           return -3;
 
-    //fprintf(stderr,"7\n");
-#define d(x) fprintf(stderr,#x "\n")
-    direntry=get_direntry_for_mapping(s,mapping);
+    while (offset < size) {
+       uint32_t c1;
+       int rest_size = (size - offset > s->cluster_size ?
+               s->cluster_size : size - offset);
+       int ret;
 
-    //d(8);
+       c1 = modified_fat_get(s, c);
 
-    assert(action==WRITE_FAT || action==WRITE_DIRENTRY || action==WRITE_DATA);
+       assert((size - offset == 0 && fat_eof(s, c)) ||
+               (size > offset && c >=2 && !fat_eof(s, c)));
+       assert(size >= 0);
 
-    //d(9);
-    //fprintf(stderr,"mapping: 0x%x s=0x%x\n",(uint32_t)mapping,(uint32_t)s);
-    /*fprintf(stderr,"commit? file=%s, action=%s\n",
-           mapping->filename,action==WRITE_FAT?"fat":action==WRITE_DIRENTRY?"direntry":"data");*/
+       ret = vvfat_read(s->bs, cluster2sector(s, c),
+           cluster, (rest_size + 0x1ff) / 0x200);
 
-    //d(10);
-    if(s->action[2]==WRITE_UNDEFINED) {
-       int i;
-       for(i=2;i>0 && s->action[i-1]==WRITE_UNDEFINED;i--);
-       if(i>0 && action!=s->action[i-1])
-           s->action[i]=action;
-       assert(i<2 || s->action[0]!=s->action[2]);
+       if (ret < 0)
+           return ret;
+
+       if (write(fd, cluster, rest_size) < 0)
+           return -2;
+
+       offset += rest_size;
+       c = c1;
     }
-    //d(11);
-    
-    if(mapping_is_consistent(s,mapping)==0) {
-       uint32_t cluster_num=begin_of_direntry(direntry);
-       off_t remaining_bytes=le32_to_cpu(direntry->size);
-       //fprintf(stderr,"the data for %s was found consistent\n",mapping->filename);
-       while(remaining_bytes>0) {
-           commit_t* commit=get_commit_for_cluster(s,cluster_num);
-           if(!commit)
-               continue;
-               
-           //fprintf(stderr,"commit_cluster %d (%d), remaining: %d\n",cluster_num,s->max_fat_value-15,(int)remaining_bytes);
-           assert(cluster_num>1);
-           assert(cluster_num<s->max_fat_value-15);
-           if(commit_cluster(s,cluster_num)) {
-               fprintf(stderr,"error committing cluster %d\n",cluster_num);
-               return -1;
-           }
-           cluster_num=fat_get(s,cluster_num);
-           remaining_bytes-=s->cluster_size;
-           /* TODO: if(action==s->action[2]) {
-               commit_t* commit=get_commit_for_cluster(s,cluster_num);
-               commit_remove(s,commit);
-           } */
+
+    ftruncate(fd, size);
+    close(fd);
+
+    return commit_mappings(s, first_cluster, dir_index);
+}
+
+#ifdef DEBUG
+/* test, if all mappings point to valid direntries */
+static void check1(BDRVVVFATState* s)
+{
+    int i;
+    for (i = 0; i < s->mapping.next; i++) {
+       mapping_t* mapping = array_get(&(s->mapping), i);
+       if (mapping->mode & MODE_DELETED) {
+           fprintf(stderr, "deleted\n");
+           continue;
+       }
+       assert(mapping->dir_index >= 0);
+       assert(mapping->dir_index < s->directory.next);
+       direntry_t* direntry = array_get(&(s->directory), mapping->dir_index);
+       assert(mapping->begin == begin_of_direntry(direntry) || mapping->first_mapping_index >= 0);
+       if (mapping->mode & MODE_DIRECTORY) {
+           assert(mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster * (mapping->end - mapping->begin) <= s->directory.next);
+           assert((mapping->info.dir.first_dir_index % (0x10 * s->sectors_per_cluster)) == 0);
        }
     }
-    //print_mappings(s);
-    //fprintf(stderr,"finish vvfat_write\n");
-    return 0;
 }
 
-static int vvfat_write(BlockDriverState *bs, int64_t sector_num, 
-                    const uint8_t *buf, int nb_sectors)
+/* test, if all direntries have mappings */
+static void check2(BDRVVVFATState* s)
 {
-    BDRVVVFATState *s = bs->opaque;
     int i;
+    int first_mapping = -1;
 
-    /* fprintf(stderr,"vvfat_write %d+%d (%s)\n",(int)sector_num,nb_sectors,
-                   (sector_num>=s->faked_sectors?"data":
-                    (sector_num>=s->first_sectors_number+2*s->sectors_per_fat?"directory":
-                     (sector_num>=s->first_sectors_number+s->sectors_per_fat?"fat 2":
-                      (sector_num>=s->first_sectors_number?"fat 1":"boot sector"))))); */
+    for (i = 0; i < s->directory.next; i++) {
+       direntry_t* direntry = array_get(&(s->directory), i);
 
-    for(i=0;i<nb_sectors;i++,sector_num++,buf+=0x200) {
-       print_changed_sector(bs,sector_num,buf);
+       if (is_short_name(direntry) && begin_of_direntry(direntry)) {
+           mapping_t* mapping = find_mapping_for_cluster(s, begin_of_direntry(direntry));
+           assert(mapping);
+           assert(mapping->dir_index == i || is_dot(direntry));
+           assert(mapping->begin == begin_of_direntry(direntry) || is_dot(direntry));
+       }
 
-       if(sector_num<s->first_sectors_number) {
-           /* change the bootsector or partition table? no! */
-           return -1;
-       } else if(sector_num<s->first_sectors_number+s->sectors_per_fat) {
-           /* FAT 1 */
-           int fat_entries_per_cluster=s->cluster_size*8/s->fat_type;
-           int first_cluster=(sector_num-s->first_sectors_number)*fat_entries_per_cluster,i;
-           mapping_t* mapping=0;
-
-           /* write back */
-           memcpy(s->fat.pointer+0x200*(sector_num-s->first_sectors_number),
-                   buf,0x200);
-
-           /* for each changed FAT entry, */
-           for(i=0;i<fat_entries_per_cluster;i++) {
-               int new_value;
-               
-               /* TODO: MODE_DIRENTRY */
-               if(first_cluster+i<s->sectors_for_directory/s->sectors_per_cluster)
-                   continue;
+       if ((i % (0x10 * s->sectors_per_cluster)) == 0) {
+           /* cluster start */
+           int j, count = 0;
 
-               new_value=fat_get(s,first_cluster+i);
-
-               /* check the current fat entry */
-               if(new_value<2 || (new_value>=s->max_fat_value-0xf && !fat_eof(s,new_value))) {
-                   /* free, reserved or bad cluster */
-                   mapping=find_mapping_for_cluster(s,first_cluster+i);
-                   //assert(!mapping || mapping->mode==MODE_DELETED);
-                   if(mapping && mapping->mode==MODE_DELETED &&
-                           first_cluster+i+1==mapping->end)
-                       array_remove(&(s->mapping),mapping-(mapping_t*)s->mapping.pointer);
-                   mapping=0;
+           for (j = 0; j < s->mapping.next; j++) {
+               mapping_t* mapping = array_get(&(s->mapping), j);
+               if (mapping->mode & MODE_DELETED)
                    continue;
-               }
-
-               /* get the mapping for the current entry */
-               if(!mapping || mapping->begin>new_value || mapping->end<=new_value) {
-                   mapping=find_mapping_for_cluster(s,first_cluster+i);
-               }
-
-               print_mappings(s);
-               fprintf(stderr,"fat_get(%d)=%d\n",first_cluster+i,new_value);
-               /* TODO: what if there's no mapping? this is valid. */
-               /* TODO: refactor the rest of this clause so it can be called when the direntry changes, too */
-               assert(mapping);
-
-               if(new_value>1 && new_value<s->max_fat_value-0xf) {
-                   /* the cluster new_value points to is valid */
-
-                   if(first_cluster+i+1==new_value) {
-                       /* consecutive cluster */
-                       if(mapping->end<=new_value)
-                           mapping->end=new_value+1;
-                   } else {
-                       mapping_t* next_mapping;
-                       
-                       /* the current mapping ends here */
-                       mapping->end=first_cluster+i+1;
-                       
-                       /* the next mapping */
-                       next_mapping=find_mapping_for_cluster(s,new_value);
-                       if(next_mapping) {
-                           assert(mapping!=next_mapping);
-                           /* assert next mapping's filename is the same */
-                           assert(next_mapping->filename==mapping->filename);
-                           assert(next_mapping->dir_index==mapping->dir_index);
-                           /* assert next mapping is MODIFIED or UNDEFINED */
-                           assert(next_mapping->mode==MODE_MODIFIED || next_mapping->mode==MODE_UNDEFINED);
-                       } else {
-                           int index=find_mapping_for_cluster_aux(s,new_value,0,s->mapping.next);
-                           next_mapping=array_insert(&(s->mapping),index,1);
-                           next_mapping->filename=mapping->filename;
-                           next_mapping->dir_index=mapping->dir_index;
-                           next_mapping->mode=MODE_MODIFIED;
-                           next_mapping->begin=0;
+               if (mapping->mode & MODE_DIRECTORY) {
+                   if (mapping->info.dir.first_dir_index <= i && mapping->info.dir.first_dir_index + 0x10 * s->sectors_per_cluster > i) {
+                       assert(++count == 1);
+                       if (mapping->first_mapping_index == -1)
+                           first_mapping = array_index(&(s->mapping), mapping);
+                       else
+                           assert(first_mapping == mapping->first_mapping_index);
+                       if (mapping->info.dir.parent_mapping_index < 0)
+                           assert(j == 0);
+                       else {
+                           mapping_t* parent = array_get(&(s->mapping), mapping->info.dir.parent_mapping_index);
+                           assert(parent->mode & MODE_DIRECTORY);
+                           assert(parent->info.dir.first_dir_index < mapping->info.dir.first_dir_index);
                        }
-                       /* adjust offset of next mapping */
-                       next_mapping->offset=mapping->offset+mapping->end-mapping->begin;
-                       /* set begin and possible end */
-                       if(next_mapping->begin!=new_value) {
-                           next_mapping->begin=new_value;
-                           next_mapping->end=new_value+1;
-                       }
-                       if(commit_data_if_consistent(s,mapping,WRITE_FAT))
-                           return -4;
-                       mapping=0;
                    }
-               } else if(fat_eof(s,new_value)) {
-                   /* the last cluster of the file */
-                   mapping->end=first_cluster+i+1;
-                   if(commit_data_if_consistent(s,mapping,WRITE_FAT))
-                       return -4;
-                   mapping=0;
                }
            }
-       } else if(sector_num<s->first_sectors_number+2*s->sectors_per_fat) {
-           /* FAT 2: check if it is the same as FAT 1 */
-           if(memcmp(array_get(&(s->fat),sector_num-s->first_sectors_number),buf,0x200))
-               return -1; /* mismatch */
-       } else if(sector_num<s->faked_sectors) {
-           /* direntry */
-           /* - if they are in a directory, check if the entry has changed.
-            *   if yes, look what has changed (different strategies for name,
-            *   begin & size).
-            *
-            *   if it is new (old entry is only 0's or has E5 at the start),
-            *   create it, and also create mapping, but in a special mode
-            *   "undefined", because we cannot know which clusters belong
-            *   to it yet.
-            *
-            *   if it is zeroed, or has E5 at the start, look if has just
-            *   moved. If yes, copy the entry to the new position. If no,
-            *   delete the file.
-            */
-           mapping_t* dir_mapping=find_mapping_for_cluster(s,sector2cluster(s,sector_num));
-           direntry_t *original=array_get(&(s->directory),sector_num-s->first_sectors_number-2*s->sectors_per_fat);
-           direntry_t *new_=(direntry_t*)buf;
-           int first_dir_index=(sector_num-s->first_sectors_number-2*s->sectors_per_fat)*0x200/0x20;
-           int j;
+           if (count == 0)
+               first_mapping = -1;
+       }
+    }
+}
+#endif
 
-#if 0
-           fprintf(stderr,"direntry: consistency check\n");
+static int handle_renames_and_mkdirs(BDRVVVFATState* s)
+{
+    int i;
 
-           if(s->commit.next==0) {
-               consistency_check1(s);
-               consistency_check2(s);
-               consistency_check3(s);
-           }
+#ifdef DEBUG
+    fprintf(stderr, "handle_renames\n");
+    for (i = 0; i < s->commits.next; i++) {
+       commit_t* commit = array_get(&(s->commits), i);
+       fprintf(stderr, "%d, %s (%d, %d)\n", i, commit->path ? commit->path : "(null)", commit->param.rename.cluster, commit->action);
+    }
 #endif
 
-           assert(sizeof(direntry_t)==0x20);
-
-           for(j=0;j<0x200/0x20;j++) {
-               //fprintf(stderr,"compare direntry %d: 0x%x,0x%x\n",j,(uint32_t)original+j,(uint32_t)new_+j);
-               if(memcmp(original+j,new_+j,sizeof(direntry_t))) {
-                   //fprintf(stderr,"different\n");
-                   /* TODO: in create_short_filename, 0xe5->0x05 is not yet handled! */
-                   if(direntry_is_free(original+j)) {
-                       mapping_t* mapping;
-                       char buffer[4096];
-                       int fd,i;
-
-                       if(new_[j].attributes==0xf)
-                           continue; /* long entry */
-
-                       print_mappings(s);
-                       //fprintf(stderr,"sector: %d cluster: %d\n",(int)sector_num,(int)sector2cluster(s,sector_num));
-
-                       /* construct absolute path */
-                       strncpy(buffer,dir_mapping->filename,4096);
-                       i=strlen(buffer);
-                       if(i+2>=4096)
-                               return -1;
-                       buffer[i]='/';
-                       if(long2unix_name(buffer+i+1,4096-i-1,new_+j))
-                               return -2;
-
-                       /* new file/directory */
-                       if(new_[j].attributes&0x10) {
-#ifdef _WIN32
-#define SEVENFIVEFIVE
+    for (i = 0; i < s->commits.next;) {
+       commit_t* commit = array_get(&(s->commits), i);
+       if (commit->action == ACTION_RENAME) {
+           mapping_t* mapping = find_mapping_for_cluster(s,
+                   commit->param.rename.cluster);
+           char* old_path = mapping->path;
+
+           assert(commit->path);
+           mapping->path = commit->path;
+           if (rename(old_path, mapping->path))
+               return -2;
+
+           if (mapping->mode & MODE_DIRECTORY) {
+               int l1 = strlen(mapping->path);
+               int l2 = strlen(old_path);
+               int diff = l1 - l2;
+               direntry_t* direntry = array_get(&(s->directory),
+                       mapping->info.dir.first_dir_index);
+               uint32_t c = mapping->begin;
+               int i = 0;
+
+               /* recurse */
+               while (!fat_eof(s, c)) {
+                   do {
+                       direntry_t* d = direntry + i;
+
+                       if (is_file(d) || (is_directory(d) && !is_dot(d))) {
+                           mapping_t* m = find_mapping_for_cluster(s,
+                                   begin_of_direntry(d));
+                           int l = strlen(m->path);
+                           char* new_path = malloc(l + diff + 1);
+
+                           assert(!strncmp(m->path, mapping->path, l2));
+
+                           strcpy(new_path, mapping->path);
+                           strcpy(new_path + l1, m->path + l2);
+
+                           schedule_rename(s, m->begin, new_path);
+                       }
+                       i++;
+                   } while((i % (0x10 * s->sectors_per_cluster)) != 0);
+                   c = fat_get(s, c);
+               }
+           }
+
+           free(old_path);
+           array_remove(&(s->commits), i);
+           continue;
+       } else if (commit->action == ACTION_MKDIR) {
+           mapping_t* mapping;
+           int j, parent_path_len;
+
+#ifdef __MINGW32__
+            if (mkdir(commit->path))
+                return -5;
 #else
-#define SEVENFIVEFIVE ,0755
+            if (mkdir(commit->path, 0755))
+                return -5;
 #endif
-                           if(mkdir(buffer SEVENFIVEFIVE))
-                               return -3;
-                           /* TODO: map direntry.begin as directory, together with new array_t direntries */
-                           assert(0);
-                       } else {
-                           fd=open(buffer,O_CREAT|O_EXCL,0644);
-                           if(!fd)
-                               return -3;
-                           close(fd);
-                       }
 
-                       /* create mapping */
-                       i=find_mapping_for_cluster_aux(s,begin_of_direntry(new_+j),0,s->mapping.next);
-                       mapping=array_insert(&(s->mapping),i,1);
-                       mapping->filename=strdup(buffer);
-                       mapping->offset=0;
-                       /* back pointer to direntry */
-                       mapping->dir_index=first_dir_index+j;
-                       /* set mode to modified */
-                       mapping->mode=MODE_MODIFIED;
-                       /* set begin to direntry.begin */
-                       mapping->begin=begin_of_direntry(new_+j);
-                       /* set end to begin+1 */
-                       mapping->end=mapping->begin+1;
-                       /* commit file contents */
-                       if(commit_data_if_consistent(s,mapping,WRITE_DIRENTRY)) {
-                           fprintf(stderr,"error committing file contents for new file %s!\n",buffer);
-                           return -4;
+           mapping = insert_mapping(s, commit->param.mkdir.cluster,
+                   commit->param.mkdir.cluster + 1);
+           if (mapping == NULL)
+               return -6;
+
+           mapping->mode = MODE_DIRECTORY;
+           mapping->read_only = 0;
+           mapping->path = commit->path;
+           j = s->directory.next;
+           assert(j);
+           insert_direntries(s, s->directory.next,
+                   0x10 * s->sectors_per_cluster);
+           mapping->info.dir.first_dir_index = j;
+
+           parent_path_len = strlen(commit->path)
+               - strlen(get_basename(commit->path)) - 1;
+           for (j = 0; j < s->mapping.next; j++) {
+               mapping_t* m = array_get(&(s->mapping), j);
+               if (m->first_mapping_index < 0 && m != mapping &&
+                       !strncmp(m->path, mapping->path, parent_path_len) &&
+                       strlen(m->path) == parent_path_len)
+                   break;
+           }
+           assert(j < s->mapping.next);
+           mapping->info.dir.parent_mapping_index = j;
+
+           array_remove(&(s->commits), i);
+           continue;
+       }
+
+       i++;
+    }
+    return 0;
+}
+
+/*
+ * TODO: make sure that the short name is not matching *another* file
+ */
+static int handle_commits(BDRVVVFATState* s)
+{
+    int i, fail = 0;
+
+    vvfat_close_current_file(s);
+
+    for (i = 0; !fail && i < s->commits.next; i++) {
+       commit_t* commit = array_get(&(s->commits), i);
+       switch(commit->action) {
+       case ACTION_RENAME: case ACTION_MKDIR:
+           assert(0);
+           fail = -2;
+           break;
+       case ACTION_WRITEOUT: {
+           direntry_t* entry = array_get(&(s->directory),
+                   commit->param.writeout.dir_index);
+           uint32_t begin = begin_of_direntry(entry);
+           mapping_t* mapping = find_mapping_for_cluster(s, begin);
+
+           assert(mapping);
+           assert(mapping->begin == begin);
+           assert(commit->path == NULL);
+
+           if (commit_one_file(s, commit->param.writeout.dir_index,
+                       commit->param.writeout.modified_offset))
+               fail = -3;
+
+           break;
+       }
+       case ACTION_NEW_FILE: {
+           int begin = commit->param.new_file.first_cluster;
+           mapping_t* mapping = find_mapping_for_cluster(s, begin);
+           direntry_t* entry;
+           int i;
+
+           /* find direntry */
+           for (i = 0; i < s->directory.next; i++) {
+               entry = array_get(&(s->directory), i);
+               if (is_file(entry) && begin_of_direntry(entry) == begin)
+                   break;
+           }
+
+           if (i >= s->directory.next) {
+               fail = -6;
+               continue;
+           }
+
+           /* make sure there exists an initial mapping */
+           if (mapping && mapping->begin != begin) {
+               mapping->end = begin;
+               mapping = NULL;
+           }
+           if (mapping == NULL) {
+               mapping = insert_mapping(s, begin, begin+1);
+           }
+           /* most members will be fixed in commit_mappings() */
+           assert(commit->path);
+           mapping->path = commit->path;
+           mapping->read_only = 0;
+           mapping->mode = MODE_NORMAL;
+           mapping->info.file.offset = 0;
+
+           if (commit_one_file(s, i, 0))
+               fail = -7;
+
+           break;
+       }
+       default:
+           assert(0);
+       }
+    }
+    if (i > 0 && array_remove_slice(&(s->commits), 0, i))
+       return -1;
+    return fail;
+}
+
+static int handle_deletes(BDRVVVFATState* s)
+{
+    int i, deferred = 1, deleted = 1;
+
+    /* delete files corresponding to mappings marked as deleted */
+    /* handle DELETEs and unused mappings (modified_fat_get(s, mapping->begin) == 0) */
+    while (deferred && deleted) {
+       deferred = 0;
+       deleted = 0;
+
+       for (i = 1; i < s->mapping.next; i++) {
+           mapping_t* mapping = array_get(&(s->mapping), i);
+           if (mapping->mode & MODE_DELETED) {
+               direntry_t* entry = array_get(&(s->directory),
+                       mapping->dir_index);
+
+               if (is_free(entry)) {
+                   /* remove file/directory */
+                   if (mapping->mode & MODE_DIRECTORY) {
+                       int j, next_dir_index = s->directory.next,
+                       first_dir_index = mapping->info.dir.first_dir_index;
+
+                       if (rmdir(mapping->path) < 0) {
+                           if (errno == ENOTEMPTY) {
+                               deferred++;
+                               continue;
+                           } else
+                               return -5;
                        }
-                   } else if(direntry_is_free(new_+j)) {
-                       assert(0);
-                       /* TODO: delete file */
-                       /* TODO: write direntry */
-                       /* TODO: modify mapping: set mode=deleted */
-                   } else {
-                       /* modified file */
-                       mapping_t* mapping=0;
-                       /* if direntry.begin has changed,
-                        * set mode to modified,
-                        * adapt begin,
-                        * adapt end */
-                       /* TODO: handle rename */
-                       assert(!memcmp(new_[j].name,original[j].name,11));
-                       //fprintf(stderr,"1\n");
-                       if(new_[j].begin!=original[j].begin || new_[j].size/s->cluster_size!=original[j].size/s->cluster_size) {
-                       //fprintf(stderr,"2\n");
-                           mapping = find_mapping_for_direntry(s,original+j);
-                       //fprintf(stderr,"3\n");
-                           if(!mapping) /* this should never happen! */
-                               return -2;
-                           mapping_modify_from_direntry(s,mapping,new_+j);
-                           //fprintf(stderr,"4\n");
-                           if(commit_data_if_consistent(s,mapping,WRITE_DIRENTRY)) {
-                               fprintf(stderr,"big error\n");
-                               return -4;
-                           }
+
+                       for (j = 1; j < s->mapping.next; j++) {
+                           mapping_t* m = array_get(&(s->mapping), j);
+                           if (m->mode & MODE_DIRECTORY &&
+                                   m->info.dir.first_dir_index >
+                                   first_dir_index &&
+                                   m->info.dir.first_dir_index <
+                                   next_dir_index)
+                               next_dir_index =
+                                   m->info.dir.first_dir_index;
                        }
-                       /* TODO: handle modified times and other attributes */
+                       remove_direntries(s, first_dir_index,
+                               next_dir_index - first_dir_index);
 
-                       //fprintf(stderr,"5: mapping=0x%x, s=0x%x, s->mapping.pointer=0x%x\n",(uint32_t)mapping,(uint32_t)s,(uint32_t)s->mapping.pointer);
-                       //fprintf(stderr,"6\n");
+                       deleted++;
                    }
+               } else {
+                   if (unlink(mapping->path))
+                       return -4;
+                   deleted++;
                }
-           }
-           /* write back direntries */
-           memcpy(original,new_,0x200);
-       } else {
-           /* data */
-           off_t sector=sector_num-s->first_sectors_number-2*s->sectors_per_fat;
-           off_t cluster=sector/s->sectors_per_cluster;
-           mapping_t* mapping=find_mapping_for_cluster(s,cluster);
-           if(mapping && mapping->mode==MODE_DELETED)
-               return -3; /* this is an error: no writes to these clusters before committed */
-           {
-               /* as of yet, undefined: put into commits */
-               commit_t* commit=create_or_get_commit_for_sector(s,sector_num);
-
-               if(!commit)
-                   return -1; /* out of memory */
-               memcpy(commit->buf+0x200*sector_offset_in_cluster(s,sector_num),buf,0x200);
-
-               //fprintf(stderr,"mapping: 0x%x\n",(uint32_t)mapping);
-               if(commit_data_if_consistent(s,mapping,WRITE_DATA))
-                   return -4;
+               DLOG(fprintf(stderr, "DELETE (%d)\n", i); print_mapping(mapping); print_direntry(entry));
+               remove_mapping(s, i);
            }
        }
     }
+
+    return 0;
+}
+
+/*
+ * synchronize mapping with new state:
+ *
+ * - copy FAT (with bdrv_read)
+ * - mark all filenames corresponding to mappings as deleted
+ * - recurse direntries from root (using bs->bdrv_read)
+ * - delete files corresponding to mappings marked as deleted
+ */
+static int do_commit(BDRVVVFATState* s)
+{
+    int ret = 0;
+
+    /* the real meat are the commits. Nothing to do? Move along! */
+    if (s->commits.next == 0)
+       return 0;
+
+    vvfat_close_current_file(s);
+
+    ret = handle_renames_and_mkdirs(s);
+    if (ret) {
+       fprintf(stderr, "Error handling renames (%d)\n", ret);
+       assert(0);
+       return ret;
+    }
+
+    /* copy FAT (with bdrv_read) */ 
+    memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
+
+    /* recurse direntries from root (using bs->bdrv_read) */
+    ret = commit_direntries(s, 0, -1);
+    if (ret) {
+       fprintf(stderr, "Fatal: error while committing (%d)\n", ret);
+       assert(0);
+       return ret;
+    }
+
+    ret = handle_commits(s);
+    if (ret) {
+       fprintf(stderr, "Error handling commits (%d)\n", ret);
+       assert(0);
+       return ret;
+    }
+
+    ret = handle_deletes(s);
+    if (ret) {
+       fprintf(stderr, "Error deleting\n");
+        assert(0);
+       return ret;
+    }
+
+    s->qcow->drv->bdrv_make_empty(s->qcow);
+
+    memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
+
+DLOG(checkpoint());
+    return 0;
+}
+
+static int try_commit(BDRVVVFATState* s)
+{
+    vvfat_close_current_file(s);
+DLOG(checkpoint());
+    if(!is_consistent(s))
+       return -1;
+    return do_commit(s);
+}
+
+static int vvfat_write(BlockDriverState *bs, int64_t sector_num, 
+                    const uint8_t *buf, int nb_sectors)
+{
+    BDRVVVFATState *s = bs->opaque; 
+    int i, ret;
+
+DLOG(checkpoint());
+
+    vvfat_close_current_file(s);
+
+    /*
+     * Some sanity checks:
+     * - do not allow writing to the boot sector
+     * - do not allow to write non-ASCII filenames
+     */
+
+    if (sector_num < s->first_sectors_number)
+       return -1;
+
+    for (i = sector2cluster(s, sector_num);
+           i <= sector2cluster(s, sector_num + nb_sectors - 1);) {
+       mapping_t* mapping = find_mapping_for_cluster(s, i);
+       if (mapping) {
+           if (mapping->read_only) {
+               fprintf(stderr, "Tried to write to write-protected file %s\n",
+                       mapping->path);
+               return -1;
+           }
+
+           if (mapping->mode & MODE_DIRECTORY) {
+               int begin = cluster2sector(s, i);
+               int end = begin + s->sectors_per_cluster, k;
+               int dir_index;
+               const direntry_t* direntries;
+               long_file_name lfn;
+
+               lfn_init(&lfn);
+
+               if (begin < sector_num)
+                   begin = sector_num;
+               if (end > sector_num + nb_sectors)
+                   end = sector_num + nb_sectors;
+               dir_index  = mapping->dir_index + 
+                   0x10 * (begin - mapping->begin * s->sectors_per_cluster);
+               direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
+
+               for (k = 0; k < (end - begin) * 0x10; k++) {
+                   /* do not allow non-ASCII filenames */
+                   if (parse_long_name(&lfn, direntries + k) < 0) {
+                       fprintf(stderr, "Warning: non-ASCII filename\n");
+                       return -1;
+                   }
+                   /* no access to the direntry of a read-only file */
+                   else if (is_short_name(direntries+k) &&
+                           (direntries[k].attributes & 1)) {
+                       if (memcmp(direntries + k,
+                                   array_get(&(s->directory), dir_index + k),
+                                   sizeof(direntry_t))) {
+                           fprintf(stderr, "Warning: tried to write to write-protected file\n");
+                           return -1;
+                       }
+                   }
+               }
+           }
+           i = mapping->end;
+       } else
+           i++;
+    }
+
+    /*
+     * Use qcow backend. Commit later.
+     */
+DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
+    ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
+    if (ret < 0) {
+       fprintf(stderr, "Error writing to qcow backend\n");
+       return ret;
+    }
+
+    for (i = sector2cluster(s, sector_num);
+           i <= sector2cluster(s, sector_num + nb_sectors - 1); i++)
+       if (i >= 0)
+           s->used_clusters[i] |= USED_ALLOCATED;
+
+DLOG(checkpoint());
+    /* TODO: add timeout */
+    try_commit(s);
+
+DLOG(checkpoint());
+    return 0;
+}
+
+static int vvfat_is_allocated(BlockDriverState *bs,
+       int64_t sector_num, int nb_sectors, int* n)
+{
+    BDRVVVFATState* s = bs->opaque;
+    *n = s->sector_count - sector_num;
+    if (*n > nb_sectors)
+       *n = nb_sectors;
+    else if (*n < 0)
+       return 0;
+    return 1;  
+}
+
+static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
+       const uint8_t* buffer, int nb_sectors) {
+    BDRVVVFATState* s = bs->opaque;
+    return try_commit(s);
+}
+
+static void write_target_close(BlockDriverState *bs) {
+    BDRVVVFATState* s = bs->opaque;
+    bdrv_delete(s->qcow);
+    free(s->qcow_filename);
+}
+
+static BlockDriver vvfat_write_target = {
+    "vvfat_write_target", 0, NULL, NULL, NULL,
+    write_target_commit,
+    write_target_close,
+    NULL, NULL, NULL
+};
+
+static int enable_write_target(BDRVVVFATState *s)
+{
+    int size = sector2cluster(s, s->sector_count);
+    s->used_clusters = calloc(size, 1);
+
+    array_init(&(s->commits), sizeof(commit_t));
+
+    s->qcow_filename = malloc(1024);
+    strcpy(s->qcow_filename, "/tmp/vl.XXXXXX");
+    get_tmp_filename(s->qcow_filename, strlen(s->qcow_filename) + 1);
+    if (bdrv_create(&bdrv_qcow,
+               s->qcow_filename, s->sector_count, "fat:", 0) < 0)
+       return -1;
+    s->qcow = bdrv_new("");
+    if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
+       return -1;
+
+#ifndef _WIN32
+    unlink(s->qcow_filename);
+#endif
+
+    s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1);
+    s->bs->backing_hd->drv = &vvfat_write_target;
+    s->bs->backing_hd->opaque = s;
+
     return 0;
 }
 
@@ -1725,8 +2758,8 @@ static void vvfat_close(BlockDriverState *bs)
     array_free(&(s->fat));
     array_free(&(s->directory));
     array_free(&(s->mapping));
-    if(s->cluster)
-        free(s->cluster);
+    if(s->cluster_buffer)
+        free(s->cluster_buffer);
 }
 
 BlockDriver bdrv_vvfat = {
@@ -1737,6 +2770,36 @@ BlockDriver bdrv_vvfat = {
     vvfat_read,
     vvfat_write,
     vvfat_close,
+    NULL,
+    vvfat_is_allocated
 };
 
+#ifdef DEBUG
+static void checkpoint() {
+    assert(((mapping_t*)array_get(&(vvv->mapping), 0))->end == 2);
+    check1(vvv);
+    check2(vvv);
+    assert(!vvv->current_mapping || vvv->current_fd || (vvv->current_mapping->mode & MODE_DIRECTORY));
+#if 0
+    if (((direntry_t*)vvv->directory.pointer)[1].attributes != 0xf)
+       fprintf(stderr, "Nonono!\n");
+    mapping_t* mapping;
+    direntry_t* direntry;
+    assert(vvv->mapping.size >= vvv->mapping.item_size * vvv->mapping.next);
+    assert(vvv->directory.size >= vvv->directory.item_size * vvv->directory.next);
+    if (vvv->mapping.next<47)
+       return;
+    assert((mapping = array_get(&(vvv->mapping), 47)));
+    assert(mapping->dir_index < vvv->directory.next);
+    direntry = array_get(&(vvv->directory), mapping->dir_index);
+    assert(!memcmp(direntry->name, "USB     H  ", 11) || direntry->name[0]==0);
+#endif
+    return;
+    /* avoid compiler warnings: */
+    hexdump(NULL, 100);
+    remove_mapping(vvv, NULL);
+    print_mapping(NULL);
+    print_direntry(NULL);
+}
+#endif
 
index 18eaf46..6924cee 100644 (file)
 #include <sys/disk.h>
 #endif
 
+#ifdef CONFIG_COCOA
+#include <paths.h>
+#include <sys/param.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/storage/IOMediaBSDClient.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/storage/IOCDMedia.h>
+//#include <IOKit/storage/IOCDTypes.h>
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
 static BlockDriverState *bdrv_first;
 static BlockDriver *first_drv;
 
+#ifdef CONFIG_COCOA
+static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
+static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
+
+kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
+{
+    kern_return_t       kernResult; 
+    mach_port_t     masterPort;
+    CFMutableDictionaryRef  classesToMatch;
+
+    kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
+    if ( KERN_SUCCESS != kernResult ) {
+        printf( "IOMasterPort returned %d\n", kernResult );
+    }
+    
+    classesToMatch = IOServiceMatching( kIOCDMediaClass ); 
+    if ( classesToMatch == NULL ) {
+        printf( "IOServiceMatching returned a NULL dictionary.\n" );
+    } else {
+    CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
+    }
+    kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
+    if ( KERN_SUCCESS != kernResult )
+    {
+        printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
+    }
+    
+    return kernResult;
+}
+
+kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
+{
+    io_object_t     nextMedia;
+    kern_return_t   kernResult = KERN_FAILURE;
+    *bsdPath = '\0';
+    nextMedia = IOIteratorNext( mediaIterator );
+    if ( nextMedia )
+    {
+        CFTypeRef   bsdPathAsCFString;
+    bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
+        if ( bsdPathAsCFString ) {
+            size_t devPathLength;
+            strcpy( bsdPath, _PATH_DEV );
+            strcat( bsdPath, "r" );
+            devPathLength = strlen( bsdPath );
+            if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
+                kernResult = KERN_SUCCESS;
+            }
+            CFRelease( bsdPathAsCFString );
+        }
+        IOObjectRelease( nextMedia );
+    }
+    
+    return kernResult;
+}
+
+#endif
+
 void bdrv_register(BlockDriver *bdrv)
 {
     bdrv->next = first_drv;
@@ -80,13 +150,19 @@ int bdrv_create(BlockDriver *drv,
 }
 
 #ifdef _WIN32
-static void get_tmp_filename(char *filename, int size)
+void get_tmp_filename(char *filename, int size)
 {
+    char* p = strrchr(filename, '/');
+
+    if (p == NULL)
+       return;
+
     /* XXX: find a better function */
-    tmpnam(filename);
+    tmpnam(p);
+    *p = '/';
 }
 #else
-static void get_tmp_filename(char *filename, int size)
+void get_tmp_filename(char *filename, int size)
 {
     int fd;
     /* XXX: race condition possible */
@@ -118,6 +194,12 @@ static BlockDriver *find_image_format(const char *filename)
                 bufsize = sectorsize;
         }
 #endif
+#ifdef CONFIG_COCOA
+        u_int32_t   blockSize = 512;
+        if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
+            bufsize = blockSize;
+        }
+#endif
         buf = qemu_malloc(bufsize);
         if (!buf)
             return NULL;
@@ -145,6 +227,32 @@ static BlockDriver *find_image_format(const char *filename)
 
 int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
 {
+#ifdef CONFIG_COCOA
+    if ( strncmp( filename, "/dev/cdrom", 10 ) == 0 ) {
+        kern_return_t kernResult;
+        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 */
+            fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
+            if (fd < 0) {
+                bsdPath[strlen(bsdPath)-1] = '1';
+            } else {
+                close(fd);
+            }
+            filename = bsdPath;
+        }
+        
+        if ( mediaIterator )
+            IOObjectRelease( mediaIterator );
+    }
+#endif
     return bdrv_open2(bs, filename, snapshot, NULL);
 }
 
@@ -292,6 +400,10 @@ int bdrv_commit(BlockDriverState *bs)
             i += n;
         }
     }
+
+    if (bs->drv->bdrv_make_empty)
+       return bs->drv->bdrv_make_empty(bs);
+
     return 0;
 }
 
@@ -342,6 +454,9 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
         return -1;
     if (bs->read_only)
         return -1;
+    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
+        memcpy(bs->boot_sector_data, buf, 512);   
+    }
     return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors);
 }
 
@@ -567,7 +682,11 @@ static int raw_open(BlockDriverState *bs, const char *filename)
 #ifdef DIOCGMEDIASIZE
        if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
 #endif
-           size = lseek(fd, 0LL, SEEK_END);
+#ifdef CONFIG_COCOA
+        size = LONG_LONG_MAX;
+#else
+        size = lseek(fd, 0LL, SEEK_END);
+#endif
     } else
 #endif
     {
index 03744f7..e303816 100644 (file)
@@ -39,6 +39,7 @@ struct BlockDriver {
     int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
                              int nb_sectors, int *pnum);
     int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
+    int (*bdrv_make_empty)(BlockDriverState *bs);
     struct BlockDriver *next;
 };
 
@@ -74,4 +75,6 @@ struct BlockDriverState {
     BlockDriverState *next;
 };
 
+void get_tmp_filename(char *filename, int size);
+
 #endif /* BLOCK_INT_H */
index d41517b..27773e9 100644 (file)
@@ -47,6 +47,9 @@ int gArgc;
 char **gArgv;
 DisplayState current_ds;
 
+int grab = 0;
+int modifiers_state[256];
+
 /* main defined in qemu/vl.c */
 int qemu_main(int argc, char **argv);
 
@@ -171,63 +174,175 @@ static void cocoa_resize(DisplayState *ds, int w, int h)
  ------------------------------------------------------
 */
 
-static int keymap[] =
+int keymap[] =
 {
-    30, //'a' 0x0
-    31,  //'s'
-    32,  //'d'
-    33,  //'f'
-    35,  //'h'
-    34,  //'g'
-    44,  //'z'
-    45,  //'x'
-    46,  //'c'
-    47,  //'v'
-    0,   // 0  0x0a
-    48,  //'b'
-    16,  //'q'
-    17,  //'w'
-    18,  //'e'
-    19,  //'r' 
-    21,  //'y' 0x10
-    20,  //'t'
-    2,  //'1'
-    3,  //'2'
-    4,  //'3'
-    5,  //'4'
-    7,  //'6'
-    6,  //'5'
-    0,  //'='
-    10,  //'9'
-    8,  //'7' 0x1A
-    0,  //'-' 
-    9,  //'8' 
-    11,  //'0' 
-    27,  //']' 
-    24,  //'o' 
-    22,  //'u' 0x20
-    26,  //'['
-    23,  //'i'
-    25,  //'p'
-    28,  //'\n'
-    38,  //'l'
-    36,  //'j'
-    40,  //'"'
-    37,  //'k'
-    39,  //';'
-    15,  //'\t' 0x30
-    0,  //' '
-    0,  //'`'
-    14,  //'<backspace>'
-    0,  //'' 0x34
-    0,  //'<esc>'
-    0,  //'<esc>'
-    /* Not completed to finish see http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */
+//  SdlI    macI    macH    SdlH    104xtH  104xtC  sdl
+    30, //  0       0x00    0x1e            A       QZ_a
+    31, //  1       0x01    0x1f            S       QZ_s
+    32, //  2       0x02    0x20            D       QZ_d
+    33, //  3       0x03    0x21            F       QZ_f
+    35, //  4       0x04    0x23            H       QZ_h
+    34, //  5       0x05    0x22            G       QZ_g
+    44, //  6       0x06    0x2c            Z       QZ_z
+    45, //  7       0x07    0x2d            X       QZ_x
+    46, //  8       0x08    0x2e            C       QZ_c
+    47, //  9       0x09    0x2f            V       QZ_v
+    0,  //  10      0x0A    Undefined
+    48, //  11      0x0B    0x30            B       QZ_b
+    16, //  12      0x0C    0x10            Q       QZ_q
+    17, //  13      0x0D    0x11            W       QZ_w
+    18, //  14      0x0E    0x12            E       QZ_e
+    19, //  15      0x0F    0x13            R       QZ_r
+    21, //  16      0x10    0x15            Y       QZ_y
+    20, //  17      0x11    0x14            T       QZ_t
+    2,  //  18      0x12    0x02            1       QZ_1
+    3,  //  19      0x13    0x03            2       QZ_2
+    4,  //  20      0x14    0x04            3       QZ_3
+    5,  //  21      0x15    0x05            4       QZ_4
+    7,  //  22      0x16    0x07            6       QZ_6
+    6,  //  23      0x17    0x06            5       QZ_5
+    13, //  24      0x18    0x0d            =       QZ_EQUALS
+    10, //  25      0x19    0x0a            9       QZ_9
+    8,  //  26      0x1A    0x08            7       QZ_7
+    12, //  27      0x1B    0x0c            -       QZ_MINUS
+    9,  //  28      0x1C    0x09            8       QZ_8
+    11, //  29      0x1D    0x0b            0       QZ_0
+    27, //  30      0x1E    0x1b            ]       QZ_RIGHTBRACKET
+    24, //  31      0x1F    0x18            O       QZ_o
+    22, //  32      0x20    0x16            U       QZ_u
+    26, //  33      0x21    0x1a            [       QZ_LEFTBRACKET
+    23, //  34      0x22    0x17            I       QZ_i
+    25, //  35      0x23    0x19            P       QZ_p
+    28, //  36      0x24    0x1c            ENTER   QZ_RETURN
+    38, //  37      0x25    0x26            L       QZ_l
+    36, //  38      0x26    0x24            J       QZ_j
+    40, //  39      0x27    0x28            '       QZ_QUOTE
+    37, //  40      0x28    0x25            K       QZ_k
+    39, //  41      0x29    0x27            ;       QZ_SEMICOLON
+    43, //  42      0x2A    0x2b            \       QZ_BACKSLASH
+    51, //  43      0x2B    0x33            ,       QZ_COMMA
+    53, //  44      0x2C    0x35            /       QZ_SLASH
+    49, //  45      0x2D    0x31            N       QZ_n
+    50, //  46      0x2E    0x32            M       QZ_m
+    52, //  47      0x2F    0x34            .       QZ_PERIOD
+    15, //  48      0x30    0x0f            TAB     QZ_TAB
+    57, //  49      0x31    0x39            SPACE   QZ_SPACE
+    41, //  50      0x32    0x29            `       QZ_BACKQUOTE
+    14, //  51      0x33    0x0e            BKSP    QZ_BACKSPACE
+    0,  //  52      0x34    Undefined
+    1,  //  53      0x35    0x01            ESC     QZ_ESCAPE
+    0,  //  54      0x36                            QZ_RMETA
+    0,  //  55      0x37                            QZ_LMETA
+    42, //  56      0x38    0x2a            L SHFT  QZ_LSHIFT
+    58, //  57      0x39    0x3a            CAPS    QZ_CAPSLOCK
+    56, //  58      0x3A    0x38            L ALT   QZ_LALT
+    29, //  59      0x3B    0x1d            L CTRL  QZ_LCTRL
+    54, //  60      0x3C    0x36            R SHFT  QZ_RSHIFT
+    184,//  61      0x3D    0xb8    E0,38   R ALT   QZ_RALT
+    157,//  62      0x3E    0x9d    E0,1D   R CTRL  QZ_RCTRL
+    0,  //  63      0x3F    Undefined
+    0,  //  64      0x40    Undefined
+    0,  //  65      0x41    Undefined
+    0,  //  66      0x42    Undefined
+    55, //  67      0x43    0x37            KP *    QZ_KP_MULTIPLY
+    0,  //  68      0x44    Undefined
+    78, //  69      0x45    0x4e            KP +    QZ_KP_PLUS
+    0,  //  70      0x46    Undefined
+    69, //  71      0x47    0x45            NUM     QZ_NUMLOCK
+    0,  //  72      0x48    Undefined
+    0,  //  73      0x49    Undefined
+    0,  //  74      0x4A    Undefined
+    181,//  75      0x4B    0xb5    E0,35   KP /    QZ_KP_DIVIDE
+    152,//  76      0x4C    0x9c    E0,1C   KP EN   QZ_KP_ENTER
+    0,  //  77      0x4D    undefined
+    74, //  78      0x4E    0x4a            KP -    QZ_KP_MINUS
+    0,  //  79      0x4F    Undefined
+    0,  //  80      0x50    Undefined
+    0,  //  81      0x51                            QZ_KP_EQUALS
+    82, //  82      0x52    0x52            KP 0    QZ_KP0
+    79, //  83      0x53    0x4f            KP 1    QZ_KP1
+    80, //  84      0x54    0x50            KP 2    QZ_KP2
+    81, //  85      0x55    0x51            KP 3    QZ_KP3
+    75, //  86      0x56    0x4b            KP 4    QZ_KP4
+    76, //  87      0x57    0x4c            KP 5    QZ_KP5
+    77, //  88      0x58    0x4d            KP 6    QZ_KP6
+    71, //  89      0x59    0x47            KP 7    QZ_KP7
+    0,  //  90      0x5A    Undefined
+    72, //  91      0x5B    0x48            KP 8    QZ_KP8
+    73, //  92      0x5C    0x49            KP 9    QZ_KP9
+    0,  //  93      0x5D    Undefined
+    0,  //  94      0x5E    Undefined
+    0,  //  95      0x5F    Undefined
+    63, //  96      0x60    0x3f            F5      QZ_F5
+    64, //  97      0x61    0x40            F6      QZ_F6
+    65, //  98      0x62    0x41            F7      QZ_F7
+    61, //  99      0x63    0x3d            F3      QZ_F3
+    66, //  100     0x64    0x42            F8      QZ_F8
+    67, //  101     0x65    0x43            F9      QZ_F9
+    0,  //  102     0x66    Undefined
+    87, //  103     0x67    0x57            F11     QZ_F11
+    0,  //  104     0x68    Undefined
+    183,//  105     0x69    0xb7            QZ_PRINT
+    0,  //  106     0x6A    Undefined
+    70, //  107     0x6B    0x46            SCROLL  QZ_SCROLLOCK
+    0,  //  108     0x6C    Undefined
+    68, //  109     0x6D    0x44            F10     QZ_F10
+    0,  //  110     0x6E    Undefined
+    88, //  111     0x6F    0x58            F12     QZ_F12
+    0,  //  112     0x70    Undefined
+    110,//  113     0x71    0x0                     QZ_PAUSE
+    210,//  114     0x72    0xd2    E0,52   INSERT  QZ_INSERT
+    199,//  115     0x73    0xc7    E0,47   HOME    QZ_HOME
+    201,//  116     0x74    0xc9    E0,49   PG UP   QZ_PAGEUP
+    211,//  117     0x75    0xd3    E0,53   DELETE  QZ_DELETE
+    62, //  118     0x76    0x3e            F4      QZ_F4
+    207,//  119     0x77    0xcf    E0,4f   END     QZ_END
+    60, //  120     0x78    0x3c            F2      QZ_F2
+    209,//  121     0x79    0xd1    E0,51   PG DN   QZ_PAGEDOWN
+    59, //  122     0x7A    0x3b            F1      QZ_F1
+    203,//  123     0x7B    0xcb    e0,4B   L ARROW QZ_LEFT
+    205,//  124     0x7C    0xcd    e0,4D   R ARROW QZ_RIGHT
+    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   
+*/
 };
 
-static int cocoa_keycode_to_qemu(int keycode)
+int cocoa_keycode_to_qemu(int keycode)
 {
-    if(sizeof(keymap) <= keycode)
+    if((sizeof(keymap)/sizeof(int)) <= keycode)
     {
         printf("(cocoa) warning unknow keycode 0x%x\n", keycode);
         return 0;
@@ -246,7 +361,6 @@ static void cocoa_refresh(DisplayState *ds)
     NSDate *distantPast;
     NSEvent *event;
     NSAutoreleasePool *pool;
-    int grab = 1;
     
     pool = [ [ NSAutoreleasePool alloc ] init ];
     distantPast = [ NSDate distantPast ];
@@ -258,41 +372,228 @@ static void cocoa_refresh(DisplayState *ds)
                         inMode: NSDefaultRunLoopMode dequeue:YES ];
         if (event != nil) {
             switch ([event type]) {
-                case NSKeyDown:
-                    if(grab)
+                case NSFlagsChanged:
                     {
                         int keycode = cocoa_keycode_to_qemu([event keyCode]);
+
+                        if (keycode)
+                        {
+                            if (keycode == 58 || keycode == 69) {
+                                /* emulate caps lock and num lock keydown and keyup */
+                                kbd_put_keycode(keycode);
+                                kbd_put_keycode(keycode | 0x80);
+                            } else if (is_active_console(vga_console)) {
+                                if (keycode & 0x80)
+                                    kbd_put_keycode(0xe0);
+                                if (modifiers_state[keycode] == 0) {
+                                    /* keydown */
+                                    kbd_put_keycode(keycode & 0x7f);
+                                    modifiers_state[keycode] = 1;
+                                } else {
+                                    /* keyup */
+                                    kbd_put_keycode(keycode | 0x80);
+                                    modifiers_state[keycode] = 0;
+                                }
+                            }
+                        }
+
+                        /* release Mouse grab when pressing ctrl+alt */
+                        if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask))
+                        {
+                            [window setTitle: @"QEMU"];
+                            [NSCursor unhide];
+                            CGAssociateMouseAndMouseCursorPosition ( TRUE );
+                            grab = 0;
+                        }
+                    }
+                    break;
+
+                case NSKeyDown:
+                    {
+                        int keycode = cocoa_keycode_to_qemu([event keyCode]);               
+                        
+                        /* handle command Key Combos */
+                        if ([event modifierFlags] & NSCommandKeyMask) {
+                            switch ([event keyCode]) {
+                                /* quit */
+                                case 12: /* q key */
+                                    /* switch to windowed View */
+                                    exit(0);
+                                    return;
+                            }
+                        }
                         
-                        if (keycode & 0x80)
-                            kbd_put_keycode(0xe0);
-                        kbd_put_keycode(keycode & 0x7f);
+                        /* handle control + alt Key Combos */
+                        if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
+                            switch (keycode) {
+                                /* toggle Monitor */
+                                case 0x02 ... 0x0a: /* '1' to '9' keys */
+                                    console_select(keycode - 0x02);
+                                    if (is_active_console(vga_console)) {
+                                        /* tell the vga console to redisplay itself */
+                                        vga_invalidate_display();
+                                    break;
+                                }
+                            }
+                        } else {
+                            /* handle standard key events */
+                            if (is_active_console(vga_console)) {
+                                if (keycode & 0x80) //check bit for e0 in front
+                                    kbd_put_keycode(0xe0);
+                                kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
+                            /* handle monitor key events */
+                            } else {
+                                switch([event keyCode]) {
+                                    case 123:
+                                        kbd_put_keysym(QEMU_KEY_LEFT);
+                                        break;
+                                    case 124:
+                                        kbd_put_keysym(QEMU_KEY_RIGHT);
+                                        break;
+                                    case 125:
+                                        kbd_put_keysym(QEMU_KEY_DOWN);
+                                        break;
+                                    case 126:
+                                        kbd_put_keysym(QEMU_KEY_UP);
+                                        break;
+                                    default:
+                                        kbd_put_keysym([[event characters] characterAtIndex:0]);
+                                        break;
+                                }
+                            }
+                        }
                     }
                     break;
+                    
                 case NSKeyUp:
-                    if(grab)
                     {
-                        int keycode = cocoa_keycode_to_qemu([event keyCode]);
-
-                        if (keycode & 0x80)
-                            kbd_put_keycode(0xe0);
-                        kbd_put_keycode(keycode | 0x80);
+                        int keycode = cocoa_keycode_to_qemu([event keyCode]);   
+                        if (is_active_console(vga_console)) {
+                            if (keycode & 0x80)
+                                kbd_put_keycode(0xe0);
+                            kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
+                        }
                     }
                     break;
-                case NSScrollWheel:
-                
+                    
+                case NSMouseMoved:
+                    if (grab) {
+                        int dx = [event deltaX];
+                        int dy = [event deltaY];
+                        int dz = [event deltaZ];
+                        int buttons = 0;
+                        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;
+                        } else {
+                            buttons |= MOUSE_EVENT_LBUTTON;
+                        }
+                        kbd_mouse_event(0, 0, 0, buttons);
+                    } else {
+                        [NSApp sendEvent: event];
+                    }
+                    break;
+                        
+                case NSLeftMouseDragged:
+                    if (grab) {
+                        int dx = [event deltaX];
+                        int dy = [event deltaY];
+                        int dz = [event deltaZ];
+                        int buttons = 0;
+                        if ([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask) { //leftclick+command simulates rightclick
+                            buttons |= MOUSE_EVENT_RBUTTON;
+                        } else {
+                            buttons |= MOUSE_EVENT_LBUTTON;
+                        }
+                        kbd_mouse_event(dx, dy, dz, buttons);
+                    }
+                    break;
+                        
                 case NSLeftMouseUp:
-                
-                case NSOtherMouseDown:
+                    if (grab) {
+                        kbd_mouse_event(0, 0, 0, 0);
+                    } else {
+                        [window setTitle: @"QEMU (Press ctrl + alt to release Mouse)"];
+                        [NSCursor hide];
+                        CGAssociateMouseAndMouseCursorPosition ( FALSE );
+                        grab = 1;
+                        //[NSApp sendEvent: event];
+                    }
+                    break;
+                        
                 case NSRightMouseDown:
-                
-                case NSOtherMouseUp:
+                    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];
+                        int dy = [event deltaY];
+                        int dz = [event deltaZ];
+                        int buttons = 0;
+                        buttons |= MOUSE_EVENT_RBUTTON;
+                        kbd_mouse_event(dx, dy, dz, buttons);
+                    }
+                    break;
+                    
                 case NSRightMouseUp:
-                
-                case NSMouseMoved:
+                    if (grab) {
+                        kbd_mouse_event(0, 0, 0, 0);
+                    } else {
+                        [NSApp sendEvent: event];
+                    }
+                    break;
+                        
                 case NSOtherMouseDragged:
-                case NSRightMouseDragged:
-                case NSLeftMouseDragged:
+                    if (grab) {
+                        int dx = [event deltaX];
+                        int dy = [event deltaY];
+                        int dz = [event deltaZ];
+                        int buttons = 0;
+                        buttons |= MOUSE_EVENT_MBUTTON;
+                        kbd_mouse_event(dx, dy, dz, buttons);
+                    }
+                    break;
+                    
+                case NSOtherMouseDown:
+                    if (grab) {
+                        int buttons = 0;
+                        buttons |= MOUSE_EVENT_MBUTTON;
+                        kbd_mouse_event(0, 0, 0, buttons);
+                    } else {
+                        [NSApp sendEvent:event];
+                    }
+                    break;
+                        
+                case NSOtherMouseUp:
+                    if (grab) {
+                        kbd_mouse_event(0, 0, 0, 0);
+                    } else {
+                        [NSApp sendEvent: event];
+                    }
+                    break;
+                        
+                case NSScrollWheel:
+                    if (grab) {
+                        int dz = [event deltaY];
+                        kbd_mouse_event(0, 0, -dz, 0);
+                    }
+                    break;
                 
                 default: [NSApp sendEvent:event];
             }
index 19a0ec9..3471193 100755 (executable)
@@ -77,6 +77,9 @@ gdbstub="yes"
 slirp="yes"
 adlib="no"
 oss="no"
+dsound="no"
+coreaudio="no"
+alsa="no"
 fmod="no"
 fmod_lib=""
 fmod_inc=""
@@ -85,6 +88,7 @@ kqemu="no"
 kernel_path=""
 cocoa="no"
 check_gfx="yes"
+check_gcc="yes"
 
 # OS specific
 targetos=`uname -s`
@@ -115,7 +119,7 @@ Darwin)
 bsd="yes"
 darwin="yes"
 ;;
-*) 
+*)
 oss="yes"
 linux="yes"
 if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
@@ -131,7 +135,7 @@ if [ "$bsd" = "yes" ] ; then
 fi
 
 # find source path
-# XXX: we assume an absolute path is given when launching configure, 
+# XXX: we assume an absolute path is given when launching configure,
 # except in './configure' case.
 source_path=${0%configure}
 source_path=${source_path%/}
@@ -143,6 +147,8 @@ fi
 
 for opt do
   case "$opt" in
+  --help|-h) show_help=yes
+  ;;
   --prefix=*) prefix=`echo $opt | cut -d '=' -f 2`
   ;;
   --interp-prefix=*) interp_prefix=`echo $opt | cut -d '=' -f 2`
@@ -171,6 +177,12 @@ for opt do
   ;;
   --disable-sdl) sdl="no"
   ;;
+  --enable-coreaudio) coreaudio="yes"
+  ;;
+  --enable-alsa) alsa="yes"
+  ;;
+  --enable-dsound) dsound="yes"
+  ;;
   --enable-fmod) fmod="yes"
   ;;
   --fmod-lib=*) fmod_lib=${opt#--fmod-lib=}
@@ -178,19 +190,21 @@ for opt do
   --fmod-inc=*) fmod_inc=${opt#--fmod-inc=}
   ;;
   --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-"
-  ;; 
+  ;;
   --disable-slirp) slirp="no"
-  ;; 
+  ;;
   --enable-adlib) adlib="yes"
-  ;; 
+  ;;
   --disable-kqemu) kqemu="no"
-  ;; 
+  ;;
   --kernel-path=*) kernel_path=${opt#--kernel-path=}
-  ;; 
-  --enable-cocoa) cocoa="yes" ; sdl="no"
-  ;; 
+  ;;
+  --enable-cocoa) cocoa="yes" ; coreaudio="yes" ; sdl="no"
+  ;;
   --disable-gfx-check) check_gfx="no"
   ;;
+  --disable-gcc-check) check_gcc="no"
+  ;;
   esac
 done
 
@@ -215,10 +229,10 @@ fi
 
 if test -z "$target_list" ; then
 # these targets are portable
-    target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu"
+    target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu arm-softmmu"
 # the following are Linux specific
     if [ "$linux" = "yes" ] ; then
-        target_list="i386-user arm-user armeb-user sparc-user ppc-user $target_list"
+        target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user $target_list"
     fi
 else
     target_list=$(echo "$target_list" | sed -e 's/,/ /g')
@@ -231,8 +245,8 @@ if test -z "$cross_prefix" ; then
 cat > $TMPC << EOF
 #include <inttypes.h>
 int main(int argc, char ** argv){
-       volatile uint32_t i=0x01234567;
-       return (*((uint8_t*)(&i))) == 0x67;
+        volatile uint32_t i=0x01234567;
+        return (*((uint8_t*)(&i))) == 0x67;
 }
 EOF
 
@@ -268,6 +282,23 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu
    have_gcc3_options="yes"
 fi
 
+# Check for gcc4
+if test "$check_gcc" = "yes" ; then
+    cat > $TMPC <<EOF
+#if __GNUC__ >= 4
+#error gcc4
+#endif
+int main(){return 0;}
+EOF
+    if ! $cc -o $TMPO $TMPC 2>/dev/null ; then
+        echo "ERROR: \"$cc\" looks like gcc 4.x"
+        echo "QEMU is known to have problems when compiled with gcc 4.x"
+        echo "It is recommended that you use gcc 3.x to build QEMU"
+        echo "To use this compiler anyway, configure with --disable-gcc-check"
+        exit 1;
+    fi
+fi
+
 ##########################################
 # SDL probe
 
@@ -319,7 +350,7 @@ fi # sdl compile test
 fi # cross compilation
 fi # -z $sdl
 
-if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
+if test x"$show_help" = x"yes" ; then
 cat << EOF
 
 Usage: configure [options]
@@ -341,12 +372,15 @@ echo "Advanced options (experts only):"
 echo "  --source-path=PATH       path of source code [$source_path]"
 echo "  --cross-prefix=PREFIX    use PREFIX for compile tools [$cross_prefix]"
 echo "  --cc=CC                  use C compiler CC [$cc]"
-echo "  --host-cc=CC             use C compiler CC [$cc] for dyngen etc."
+echo "  --host-cc=CC             use C compiler CC [$host_cc] for dyngen etc."
 echo "  --make=MAKE              use specified make [$make]"
 echo "  --static                 enable static build [$static]"
 echo "  --enable-mingw32         enable Win32 cross compilation with mingw32"
 echo "  --enable-adlib           enable Adlib emulation"
-echo "  --enable-fmod            enable FMOD audio output driver"
+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 "  --fmod-lib               path to FMOD library"
 echo "  --fmod-inc               path to FMOD includes"
 echo ""
@@ -375,20 +409,20 @@ fi
 # kqemu support
 if test $kqemu = "yes" ; then
     # test if the source code is installed
-    if test '!' -f "kqemu/Makefile" ; then 
+    if test '!' -f "kqemu/Makefile" ; then
         kqemu="no"
     fi
 fi
-  
+
 # Linux specific kqemu configuration
 if test $kqemu = "yes" -a $linux = "yes" ; then
 # find the kernel path
 if test -z "$kernel_path" ; then
 kernel_version=`uname -r`
 kernel_path="/lib/modules/$kernel_version/build"
-if test '!' -d "$kernel_path/include" ; then 
+if test '!' -d "$kernel_path/include" ; then
     kernel_path="/usr/src/linux"
-    if test '!' -d "$kernel_path/include" ; then 
+    if test '!' -d "$kernel_path/include" ; then
         echo "Could not find kernel includes in /lib/modules or /usr/src/linux - cannot build the kqemu module"
         kqemu="no"
     fi
@@ -401,7 +435,7 @@ if test $kqemu = "yes" ; then
 if test '!' -f "$kernel_path/Makefile" ; then
     echo "No Makefile file present in $kernel_path - kqemu cannot be built"
     kqemu="no"
-fi    
+fi
 
 # find build system (2.6 or legacy)
 kbuild26="yes"
@@ -439,8 +473,18 @@ if test "$sdl" != "no" ; then
 fi
 echo "mingw32 support   $mingw32"
 echo "Adlib support     $adlib"
+echo "CoreAudio support $coreaudio"
+echo "ALSA support      $alsa"
+echo "DSound support    $dsound"
 echo -n "FMOD support      $fmod"
-if test $fmod = "yes"; then
+if test "$fmod" = "yes"; then
+    if test -z $fmod_lib || test -z $fmod_inc; then
+        echo
+        echo "Error: You must specify path to FMOD library and headers"
+        echo "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so"
+        echo
+        exit 1
+    fi
     echo -n " (lib='$fmod_lib' include='$fmod_inc')"
 fi
 echo ""
@@ -568,6 +612,18 @@ if test "$oss" = "yes" ; then
   echo "CONFIG_OSS=yes" >> $config_mak
   echo "#define CONFIG_OSS 1" >> $config_h
 fi
+if test "$coreaudio" = "yes" ; then
+  echo "CONFIG_COREAUDIO=yes" >> $config_mak
+  echo "#define CONFIG_COREAUDIO 1" >> $config_h
+fi
+if test "$alsa" = "yes" ; then
+  echo "CONFIG_ALSA=yes" >> $config_mak
+  echo "#define CONFIG_ALSA 1" >> $config_h
+fi
+if test "$dsound" = "yes" ; then
+  echo "CONFIG_DSOUND=yes" >> $config_mak
+  echo "#define CONFIG_DSOUND 1" >> $config_h
+fi
 if test "$fmod" = "yes" ; then
   echo "CONFIG_FMOD=yes" >> $config_mak
   echo "CONFIG_FMOD_LIB=$fmod_lib" >> $config_mak
@@ -600,7 +656,7 @@ if [ "$bsd" = "yes" ] ; then
   echo "#define _BSD 1" >> $config_h
 fi
 
-for target in $target_list; do 
+for target in $target_list; do
 
 target_dir="$target"
 config_mak=$target_dir/config.mak
@@ -623,7 +679,7 @@ if expr $target : '.*-user' > /dev/null ; then
 fi
 
 if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \
-       -a "$sdl" = "no" -a "$cocoa" = "no" ; then
+        -a "$sdl" = "no" -a "$cocoa" = "no" ; then
     echo "ERROR: QEMU requires SDL or Cocoa for graphical output"
     echo "To build QEMU with graphical output configure with --disable-gfx-check"
     echo "Note that this will disable all output from the virtual graphics card."
@@ -690,7 +746,7 @@ elif test "$target_cpu" = "x86_64" ; then
   if test $kqemu = "yes" -a "$target_softmmu" = "yes" -a $cpu = "x86_64"  ; then
     echo "#define USE_KQEMU 1" >> $config_h
   fi
-elif test "$target_cpu" = "mips" ; then
+elif test "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" ; then
   echo "TARGET_ARCH=mips" >> $config_mak
   echo "#define TARGET_ARCH \"mips\"" >> $config_h
   echo "#define TARGET_MIPS 1" >> $config_h
index 4f1f772..b374fe8 100644 (file)
@@ -188,10 +188,10 @@ static inline void stb_p(void *ptr, int v)
 /* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
    kernel handles unaligned load/stores may give better results, but
    it is a system wide setting : bad */
-#if !defined(TARGET_WORDS_BIGENDIAN) && (defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
+#if defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
 
 /* conservative code for little endian unaligned accesses */
-static inline int lduw_p(void *ptr)
+static inline int lduw_le_p(void *ptr)
 {
 #ifdef __powerpc__
     int val;
@@ -203,7 +203,7 @@ static inline int lduw_p(void *ptr)
 #endif
 }
 
-static inline int ldsw_p(void *ptr)
+static inline int ldsw_le_p(void *ptr)
 {
 #ifdef __powerpc__
     int val;
@@ -215,7 +215,7 @@ static inline int ldsw_p(void *ptr)
 #endif
 }
 
-static inline int ldl_p(void *ptr)
+static inline int ldl_le_p(void *ptr)
 {
 #ifdef __powerpc__
     int val;
@@ -227,16 +227,16 @@ static inline int ldl_p(void *ptr)
 #endif
 }
 
-static inline uint64_t ldq_p(void *ptr)
+static inline uint64_t ldq_le_p(void *ptr)
 {
     uint8_t *p = ptr;
     uint32_t v1, v2;
-    v1 = ldl_p(p);
-    v2 = ldl_p(p + 4);
+    v1 = ldl_le_p(p);
+    v2 = ldl_le_p(p + 4);
     return v1 | ((uint64_t)v2 << 32);
 }
 
-static inline void stw_p(void *ptr, int v)
+static inline void stw_le_p(void *ptr, int v)
 {
 #ifdef __powerpc__
     __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
@@ -247,7 +247,7 @@ static inline void stw_p(void *ptr, int v)
 #endif
 }
 
-static inline void stl_p(void *ptr, int v)
+static inline void stl_le_p(void *ptr, int v)
 {
 #ifdef __powerpc__
     __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
@@ -260,54 +260,114 @@ static inline void stl_p(void *ptr, int v)
 #endif
 }
 
-static inline void stq_p(void *ptr, uint64_t v)
+static inline void stq_le_p(void *ptr, uint64_t v)
 {
     uint8_t *p = ptr;
-    stl_p(p, (uint32_t)v);
-    stl_p(p + 4, v >> 32);
+    stl_le_p(p, (uint32_t)v);
+    stl_le_p(p + 4, v >> 32);
 }
 
 /* float access */
 
-static inline float32 ldfl_p(void *ptr)
+static inline float32 ldfl_le_p(void *ptr)
 {
     union {
         float32 f;
         uint32_t i;
     } u;
-    u.i = ldl_p(ptr);
+    u.i = ldl_le_p(ptr);
     return u.f;
 }
 
-static inline void stfl_p(void *ptr, float32 v)
+static inline void stfl_le_p(void *ptr, float32 v)
 {
     union {
         float32 f;
         uint32_t i;
     } u;
     u.f = v;
-    stl_p(ptr, u.i);
+    stl_le_p(ptr, u.i);
 }
 
-static inline float64 ldfq_p(void *ptr)
+static inline float64 ldfq_le_p(void *ptr)
 {
     CPU_DoubleU u;
-    u.l.lower = ldl_p(ptr);
-    u.l.upper = ldl_p(ptr + 4);
+    u.l.lower = ldl_le_p(ptr);
+    u.l.upper = ldl_le_p(ptr + 4);
     return u.d;
 }
 
-static inline void stfq_p(void *ptr, float64 v)
+static inline void stfq_le_p(void *ptr, float64 v)
 {
     CPU_DoubleU u;
     u.d = v;
-    stl_p(ptr, u.l.lower);
-    stl_p(ptr + 4, u.l.upper);
+    stl_le_p(ptr, u.l.lower);
+    stl_le_p(ptr + 4, u.l.upper);
 }
 
-#elif defined(TARGET_WORDS_BIGENDIAN) && (!defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED))
+#else
+
+static inline int lduw_le_p(void *ptr)
+{
+    return *(uint16_t *)ptr;
+}
+
+static inline int ldsw_le_p(void *ptr)
+{
+    return *(int16_t *)ptr;
+}
+
+static inline int ldl_le_p(void *ptr)
+{
+    return *(uint32_t *)ptr;
+}
+
+static inline uint64_t ldq_le_p(void *ptr)
+{
+    return *(uint64_t *)ptr;
+}
+
+static inline void stw_le_p(void *ptr, int v)
+{
+    *(uint16_t *)ptr = v;
+}
+
+static inline void stl_le_p(void *ptr, int v)
+{
+    *(uint32_t *)ptr = v;
+}
+
+static inline void stq_le_p(void *ptr, uint64_t v)
+{
+    *(uint64_t *)ptr = v;
+}
+
+/* float access */
+
+static inline float32 ldfl_le_p(void *ptr)
+{
+    return *(float32 *)ptr;
+}
 
-static inline int lduw_p(void *ptr)
+static inline float64 ldfq_le_p(void *ptr)
+{
+    return *(float64 *)ptr;
+}
+
+static inline void stfl_le_p(void *ptr, float32 v)
+{
+    *(float32 *)ptr = v;
+}
+
+static inline void stfq_le_p(void *ptr, float64 v)
+{
+    *(float64 *)ptr = v;
+}
+#endif
+
+#if !defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
+
+static inline int lduw_be_p(void *ptr)
 {
 #if defined(__i386__)
     int val;
@@ -322,7 +382,7 @@ static inline int lduw_p(void *ptr)
 #endif
 }
 
-static inline int ldsw_p(void *ptr)
+static inline int ldsw_be_p(void *ptr)
 {
 #if defined(__i386__)
     int val;
@@ -337,7 +397,7 @@ static inline int ldsw_p(void *ptr)
 #endif
 }
 
-static inline int ldl_p(void *ptr)
+static inline int ldl_be_p(void *ptr)
 {
 #if defined(__i386__) || defined(__x86_64__)
     int val;
@@ -352,15 +412,15 @@ static inline int ldl_p(void *ptr)
 #endif
 }
 
-static inline uint64_t ldq_p(void *ptr)
+static inline uint64_t ldq_be_p(void *ptr)
 {
     uint32_t a,b;
-    a = ldl_p(ptr);
-    b = ldl_p(ptr+4);
+    a = ldl_be_p(ptr);
+    b = ldl_be_p(ptr+4);
     return (((uint64_t)a<<32)|b);
 }
 
-static inline void stw_p(void *ptr, int v)
+static inline void stw_be_p(void *ptr, int v)
 {
 #if defined(__i386__)
     asm volatile ("xchgb %b0, %h0\n"
@@ -374,7 +434,7 @@ static inline void stw_p(void *ptr, int v)
 #endif
 }
 
-static inline void stl_p(void *ptr, int v)
+static inline void stl_be_p(void *ptr, int v)
 {
 #if defined(__i386__) || defined(__x86_64__)
     asm volatile ("bswap %0\n"
@@ -390,108 +450,136 @@ static inline void stl_p(void *ptr, int v)
 #endif
 }
 
-static inline void stq_p(void *ptr, uint64_t v)
+static inline void stq_be_p(void *ptr, uint64_t v)
 {
-    stl_p(ptr, v >> 32);
-    stl_p(ptr + 4, v);
+    stl_be_p(ptr, v >> 32);
+    stl_be_p(ptr + 4, v);
 }
 
 /* float access */
 
-static inline float32 ldfl_p(void *ptr)
+static inline float32 ldfl_be_p(void *ptr)
 {
     union {
         float32 f;
         uint32_t i;
     } u;
-    u.i = ldl_p(ptr);
+    u.i = ldl_be_p(ptr);
     return u.f;
 }
 
-static inline void stfl_p(void *ptr, float32 v)
+static inline void stfl_be_p(void *ptr, float32 v)
 {
     union {
         float32 f;
         uint32_t i;
     } u;
     u.f = v;
-    stl_p(ptr, u.i);
+    stl_be_p(ptr, u.i);
 }
 
-static inline float64 ldfq_p(void *ptr)
+static inline float64 ldfq_be_p(void *ptr)
 {
     CPU_DoubleU u;
-    u.l.upper = ldl_p(ptr);
-    u.l.lower = ldl_p(ptr + 4);
+    u.l.upper = ldl_be_p(ptr);
+    u.l.lower = ldl_be_p(ptr + 4);
     return u.d;
 }
 
-static inline void stfq_p(void *ptr, float64 v)
+static inline void stfq_be_p(void *ptr, float64 v)
 {
     CPU_DoubleU u;
     u.d = v;
-    stl_p(ptr, u.l.upper);
-    stl_p(ptr + 4, u.l.lower);
+    stl_be_p(ptr, u.l.upper);
+    stl_be_p(ptr + 4, u.l.lower);
 }
 
 #else
 
-static inline int lduw_p(void *ptr)
+static inline int lduw_be_p(void *ptr)
 {
     return *(uint16_t *)ptr;
 }
 
-static inline int ldsw_p(void *ptr)
+static inline int ldsw_be_p(void *ptr)
 {
     return *(int16_t *)ptr;
 }
 
-static inline int ldl_p(void *ptr)
+static inline int ldl_be_p(void *ptr)
 {
     return *(uint32_t *)ptr;
 }
 
-static inline uint64_t ldq_p(void *ptr)
+static inline uint64_t ldq_be_p(void *ptr)
 {
     return *(uint64_t *)ptr;
 }
 
-static inline void stw_p(void *ptr, int v)
+static inline void stw_be_p(void *ptr, int v)
 {
     *(uint16_t *)ptr = v;
 }
 
-static inline void stl_p(void *ptr, int v)
+static inline void stl_be_p(void *ptr, int v)
 {
     *(uint32_t *)ptr = v;
 }
 
-static inline void stq_p(void *ptr, uint64_t v)
+static inline void stq_be_p(void *ptr, uint64_t v)
 {
     *(uint64_t *)ptr = v;
 }
 
 /* float access */
 
-static inline float32 ldfl_p(void *ptr)
+static inline float32 ldfl_be_p(void *ptr)
 {
     return *(float32 *)ptr;
 }
 
-static inline float64 ldfq_p(void *ptr)
+static inline float64 ldfq_be_p(void *ptr)
 {
     return *(float64 *)ptr;
 }
 
-static inline void stfl_p(void *ptr, float32 v)
+static inline void stfl_be_p(void *ptr, float32 v)
 {
     *(float32 *)ptr = v;
 }
 
-static inline void stfq_p(void *ptr, float64 v)
+static inline void stfq_be_p(void *ptr, float64 v)
 {
     *(float64 *)ptr = v;
 }
+
+#endif
+
+/* target CPU memory access functions */
+#if defined(TARGET_WORDS_BIGENDIAN)
+#define lduw_p(p) lduw_be_p(p)
+#define ldsw_p(p) ldsw_be_p(p)
+#define ldl_p(p) ldl_be_p(p)
+#define ldq_p(p) ldq_be_p(p)
+#define ldfl_p(p) ldfl_be_p(p)
+#define ldfq_p(p) ldfq_be_p(p)
+#define stw_p(p, v) stw_be_p(p, v)
+#define stl_p(p, v) stl_be_p(p, v)
+#define stq_p(p, v) stq_be_p(p, v)
+#define stfl_p(p, v) stfl_be_p(p, v)
+#define stfq_p(p, v) stfq_be_p(p, v)
+#else
+#define lduw_p(p) lduw_le_p(p)
+#define ldsw_p(p) ldsw_le_p(p)
+#define ldl_p(p) ldl_le_p(p)
+#define ldq_p(p) ldq_le_p(p)
+#define ldfl_p(p) ldfl_le_p(p)
+#define ldfq_p(p) ldfq_le_p(p)
+#define stw_p(p, v) stw_le_p(p, v)
+#define stl_p(p, v) stl_le_p(p, v)
+#define stq_p(p, v) stq_le_p(p, v)
+#define stfl_p(p, v) stfl_le_p(p, v)
+#define stfq_p(p, v) stfq_le_p(p, v)
 #endif
 
 /* MMU memory access macros */
@@ -637,6 +725,7 @@ void cpu_dump_state(CPUState *env, FILE *f,
                     int flags);
 
 void cpu_abort(CPUState *env, const char *fmt, ...);
+extern CPUState *first_cpu;
 extern CPUState *cpu_single_env;
 extern int code_copy_enabled;
 
@@ -644,6 +733,9 @@ extern int code_copy_enabled;
 #define CPU_INTERRUPT_HARD   0x02 /* hardware interrupt pending */
 #define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */
 #define CPU_INTERRUPT_TIMER  0x08 /* internal timer exception pending */
+#define CPU_INTERRUPT_FIQ    0x10 /* Fast interrupt pending.  */
+#define CPU_INTERRUPT_HALT   0x20 /* CPU halt wanted */
+
 void cpu_interrupt(CPUState *s, int mask);
 void cpu_reset_interrupt(CPUState *env, int mask);
 
@@ -701,9 +793,9 @@ extern uint8_t *phys_ram_base;
 extern uint8_t *phys_ram_dirty;
 
 /* physical memory access */
-#define IO_MEM_NB_ENTRIES  256
 #define TLB_INVALID_MASK   (1 << 3)
 #define IO_MEM_SHIFT       4
+#define IO_MEM_NB_ENTRIES  (1 << (TARGET_PAGE_BITS  - IO_MEM_SHIFT))
 
 #define IO_MEM_RAM         (0 << IO_MEM_SHIFT) /* hardcoded offset */
 #define IO_MEM_ROM         (1 << IO_MEM_SHIFT) /* hardcoded offset */
@@ -735,9 +827,15 @@ static inline void cpu_physical_memory_write(target_phys_addr_t addr,
 {
     cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
 }
+uint32_t ldub_phys(target_phys_addr_t addr);
+uint32_t lduw_phys(target_phys_addr_t addr);
 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 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);
 
 int cpu_memory_rw_debug(CPUState *env, target_ulong addr, 
                         uint8_t *buf, int len, int is_write);
index 912133e..665158a 100644 (file)
@@ -74,10 +74,14 @@ typedef unsigned long ram_addr_t;
 #define EXCP_INTERRUPT         0x10000 /* async interruption */
 #define EXCP_HLT        0x10001 /* hlt instruction reached */
 #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 CPU_TLB_SIZE 256
+#define TB_JMP_CACHE_BITS 12
+#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
+
+#define CPU_TLB_BITS 8
+#define CPU_TLB_SIZE (1 << CPU_TLB_BITS)
 
 typedef struct CPUTLBEntry {
     /* bit 31 to TARGET_PAGE_BITS : virtual address 
@@ -86,9 +90,36 @@ typedef struct CPUTLBEntry {
        bit 3                      : indicates that the entry is invalid
        bit 2..0                   : zero
     */
-    target_ulong address; 
+    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; 
 } CPUTLBEntry;
 
+#define CPU_COMMON                                                      \
+    struct TranslationBlock *current_tb; /* currently executing TB  */  \
+    /* soft mmu support */                                              \
+    /* in order to avoid passing too many arguments to the memory       \
+       write helpers, we store some rarely used information in the CPU  \
+       context) */                                                      \
+    unsigned long mem_write_pc; /* host pc at which the memory was      \
+                                   written */                           \
+    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];                             \
+    struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE];           \
+                                                                        \
+    /* from this point: preserved by CPU reset */                       \
+    /* ice debug support */                                             \
+    target_ulong breakpoints[MAX_BREAKPOINTS];                          \
+    int nb_breakpoints;                                                 \
+    int singlestep_enabled;                                             \
+                                                                        \
+    void *next_cpu; /* next CPU sharing TB cache */                     \
+    int cpu_index; /* CPU index (informative) */                        \
+    /* user data */                                                     \
+    void *opaque;
+
 #endif
index bdfc865..1ec49c2 100644 (file)
@@ -73,6 +73,141 @@ void cpu_resume_from_signal(CPUState *env1, void *puc)
     longjmp(env->jmp_env, 1);
 }
 
+
+static TranslationBlock *tb_find_slow(target_ulong pc,
+                                      target_ulong cs_base,
+                                      unsigned int 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;
+    phys_page2 = -1;
+    h = tb_phys_hash_func(phys_pc);
+    ptb1 = &tb_phys_hash[h];
+    for(;;) {
+        tb = *ptb1;
+        if (!tb)
+            goto not_found;
+        if (tb->pc == pc && 
+            tb->page_addr[0] == phys_page1 &&
+            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) + 
+                    TARGET_PAGE_SIZE;
+                phys_page2 = get_phys_addr_code(env, virt_page2);
+                if (tb->page_addr[1] == phys_page2)
+                    goto found;
+            } else {
+                goto found;
+            }
+        }
+        ptb1 = &tb->phys_hash_next;
+    }
+ not_found:
+    /* if no translated code available, then translate it now */
+    tb = tb_alloc(pc);
+    if (!tb) {
+        /* flush must be done */
+        tb_flush(env);
+        /* cannot fail at this point */
+        tb = tb_alloc(pc);
+        /* don't forget to invalidate previous TB info */
+        tb_invalidated_flag = 1;
+    }
+    tc_ptr = code_gen_ptr;
+    tb->tc_ptr = tc_ptr;
+    tb->cs_base = cs_base;
+    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;
+    if ((pc & TARGET_PAGE_MASK) != virt_page2) {
+        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;
+    spin_unlock(&tb_lock);
+    return tb;
+}
+
+static inline TranslationBlock *tb_find_fast(void)
+{
+    TranslationBlock *tb;
+    target_ulong cs_base, pc;
+    unsigned int flags;
+
+    /* we record a subset of the CPU state. It will
+       always be the same before a given translated block
+       is executed. */
+#if defined(TARGET_I386)
+    flags = env->hflags;
+    flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
+    cs_base = env->segs[R_CS].base;
+    pc = cs_base + env->eip;
+#elif defined(TARGET_ARM)
+    flags = env->thumb | (env->vfp.vec_len << 1)
+            | (env->vfp.vec_stride << 4);
+    if ((env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR)
+        flags |= (1 << 6);
+    cs_base = 0;
+    pc = env->regs[15];
+#elif defined(TARGET_SPARC)
+#ifdef TARGET_SPARC64
+    flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
+#else
+    flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1);
+#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);
+    cs_base = 0;
+    pc = env->nip;
+#elif defined(TARGET_MIPS)
+    flags = env->hflags & (MIPS_HFLAGS_TMASK | MIPS_HFLAG_BMASK);
+    cs_base = 0;
+    pc = env->PC;
+#else
+#error unsupported CPU
+#endif
+    tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
+    if (__builtin_expect(!tb || tb->pc != pc || tb->cs_base != cs_base ||
+                         tb->flags != flags, 0)) {
+        tb = tb_find_slow(pc, cs_base, flags);
+        /* Note: we do it here to avoid a gcc bug on Mac OS X when
+           doing it in tb_find_slow */
+        if (tb_invalidated_flag) {
+            /* as some TB could have been invalidated because
+               of memory exceptions while generating the code, we
+               must recompute the hash index here */
+            T0 = 0;
+        }
+    }
+    return tb;
+}
+
+
 /* main execution loop */
 
 int cpu_exec(CPUState *env1)
@@ -115,12 +250,64 @@ int cpu_exec(CPUState *env1)
 #ifdef __sparc__
     int saved_i7, tmp_T0;
 #endif
-    int code_gen_size, ret, interrupt_request;
+    int ret, interrupt_request;
     void (*gen_func)(void);
-    TranslationBlock *tb, **ptb;
-    target_ulong cs_base, pc;
+    TranslationBlock *tb;
     uint8_t *tc_ptr;
-    unsigned int flags;
+
+#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
+
+    cpu_single_env = env1; 
 
     /* first we save global registers */
     saved_env = env;
@@ -168,15 +355,6 @@ int cpu_exec(CPUState *env1)
     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)
-    {
-        unsigned int psr;
-        psr = env->cpsr;
-        env->CF = (psr >> 29) & 1;
-        env->NZF = (psr & 0xc0000000) ^ 0x40000000;
-        env->VF = (psr << 3) & 0x80000000;
-        env->QF = (psr >> 27) & 1;
-        env->cpsr = psr & ~CACHED_CPSR_BITS;
-    }
 #elif defined(TARGET_SPARC)
 #if defined(reg_REGWPTR)
     saved_regwptr = REGWPTR;
@@ -225,6 +403,8 @@ int cpu_exec(CPUState *env1)
                     do_interrupt(env);
 #elif defined(TARGET_SPARC)
                     do_interrupt(env->exception_index);
+#elif defined(TARGET_ARM)
+                    do_interrupt(env);
 #endif
                 }
                 env->exception_index = -1;
@@ -290,19 +470,29 @@ int cpu_exec(CPUState *env1)
                     }
 #endif
                     if (msr_ee != 0) {
-                    if ((interrupt_request & CPU_INTERRUPT_HARD)) {
+                        if ((interrupt_request & CPU_INTERRUPT_HARD)) {
                            /* Raise it */
                            env->exception_index = EXCP_EXTERNAL;
                            env->error_code = 0;
                             do_interrupt(env);
-                        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
-                       } 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_HARD;
+#ifdef __sparc__
+                            tmp_T0 = 0;
+#else
+                            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;
-                       }
+#ifdef __sparc__
+                            tmp_T0 = 0;
+#else
+                            T0 = 0;
+#endif
+                        }
                     }
 #elif defined(TARGET_MIPS)
                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
@@ -316,6 +506,11 @@ int cpu_exec(CPUState *env1)
                         env->error_code = 0;
                         do_interrupt(env);
                         env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+#ifdef __sparc__
+                        tmp_T0 = 0;
+#else
+                        T0 = 0;
+#endif
                     }
 #elif defined(TARGET_SPARC)
                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
@@ -329,13 +524,32 @@ int cpu_exec(CPUState *env1)
                            env->interrupt_request &= ~CPU_INTERRUPT_HARD;
                            do_interrupt(env->interrupt_index);
                            env->interrupt_index = 0;
+#ifdef __sparc__
+                            tmp_T0 = 0;
+#else
+                            T0 = 0;
+#endif
                        }
                    } 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) {
+                        env1->halted = 1;
+                        return EXCP_HALTED;
+                    }
+#elif defined(TARGET_ARM)
+                    if (interrupt_request & CPU_INTERRUPT_FIQ
+                        && !(env->uncached_cpsr & CPSR_F)) {
+                        env->exception_index = EXCP_FIQ;
+                        do_interrupt(env);
+                    }
+                    if (interrupt_request & CPU_INTERRUPT_HARD
+                        && !(env->uncached_cpsr & CPSR_I)) {
+                        env->exception_index = EXCP_IRQ;
+                        do_interrupt(env);
+                    }
 #endif
-                    if (interrupt_request & CPU_INTERRUPT_EXITTB) {
+                    if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
                         env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
                         /* ensure that no TB jump will be modified as
                            the program flow was changed */
@@ -352,7 +566,7 @@ int cpu_exec(CPUState *env1)
                     }
                 }
 #ifdef DEBUG_EXEC
-                if ((loglevel & CPU_LOG_EXEC)) {
+                if ((loglevel & CPU_LOG_TB_CPU)) {
 #if defined(TARGET_I386)
                     /* restore flags in standard format */
 #ifdef reg_EAX
@@ -383,9 +597,7 @@ int cpu_exec(CPUState *env1)
                     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);
 #elif defined(TARGET_ARM)
-                    env->cpsr = compute_cpsr();
                     cpu_dump_state(env, logfile, fprintf, 0);
-                    env->cpsr &= ~CACHED_CPSR_BITS;
 #elif defined(TARGET_SPARC)
                    REGWPTR = env->regbase + (env->cwp * 16);
                    env->regwptr = REGWPTR;
@@ -399,123 +611,7 @@ int cpu_exec(CPUState *env1)
 #endif
                 }
 #endif
-                /* we record a subset of the CPU state. It will
-                   always be the same before a given translated block
-                   is executed. */
-#if defined(TARGET_I386)
-                flags = env->hflags;
-                flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
-                cs_base = env->segs[R_CS].base;
-                pc = cs_base + env->eip;
-#elif defined(TARGET_ARM)
-                flags = env->thumb | (env->vfp.vec_len << 1)
-                        | (env->vfp.vec_stride << 4);
-                cs_base = 0;
-                pc = env->regs[15];
-#elif defined(TARGET_SPARC)
-#ifdef TARGET_SPARC64
-                flags = (env->pstate << 2) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
-#else
-                flags = env->psrs | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1);
-#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);
-                cs_base = 0;
-                pc = env->nip;
-#elif defined(TARGET_MIPS)
-                flags = env->hflags & MIPS_HFLAGS_TMASK;
-                cs_base = NULL;
-                pc = env->PC;
-#else
-#error unsupported CPU
-#endif
-                tb = tb_find(&ptb, pc, cs_base, 
-                             flags);
-                if (!tb) {
-                    TranslationBlock **ptb1;
-                    unsigned int h;
-                    target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
-                    
-                    
-                    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;
-                    phys_page2 = -1;
-                    h = tb_phys_hash_func(phys_pc);
-                    ptb1 = &tb_phys_hash[h];
-                    for(;;) {
-                        tb = *ptb1;
-                        if (!tb)
-                            goto not_found;
-                        if (tb->pc == pc && 
-                            tb->page_addr[0] == phys_page1 &&
-                            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) + 
-                                    TARGET_PAGE_SIZE;
-                                phys_page2 = get_phys_addr_code(env, virt_page2);
-                                if (tb->page_addr[1] == phys_page2)
-                                    goto found;
-                            } else {
-                                goto found;
-                            }
-                        }
-                        ptb1 = &tb->phys_hash_next;
-                    }
-                not_found:
-                    /* if no translated code available, then translate it now */
-                    tb = tb_alloc(pc);
-                    if (!tb) {
-                        /* flush must be done */
-                        tb_flush(env);
-                        /* cannot fail at this point */
-                        tb = tb_alloc(pc);
-                        /* don't forget to invalidate previous TB info */
-                        ptb = &tb_hash[tb_hash_func(pc)];
-                        T0 = 0;
-                    }
-                    tc_ptr = code_gen_ptr;
-                    tb->tc_ptr = tc_ptr;
-                    tb->cs_base = cs_base;
-                    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;
-                    if ((pc & TARGET_PAGE_MASK) != virt_page2) {
-                        phys_page2 = get_phys_addr_code(env, virt_page2);
-                    }
-                    tb_link_phys(tb, phys_pc, phys_page2);
-
-                found:
-                    if (tb_invalidated_flag) {
-                        /* as some TB could have been invalidated because
-                           of memory exceptions while generating the code, we
-                           must recompute the hash index here */
-                        ptb = &tb_hash[tb_hash_func(pc)];
-                        while (*ptb != NULL)
-                            ptb = &(*ptb)->hash_next;
-                        T0 = 0;
-                    }
-                    /* we add the TB in the virtual pc hash table */
-                    *ptb = tb;
-                    tb->hash_next = NULL;
-                    tb_link(tb);
-                    spin_unlock(&tb_lock);
-                }
+                tb = tb_find_fast();
 #ifdef DEBUG_EXEC
                 if ((loglevel & CPU_LOG_EXEC)) {
                     fprintf(logfile, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
@@ -526,9 +622,12 @@ int cpu_exec(CPUState *env1)
 #ifdef __sparc__
                 T0 = tmp_T0;
 #endif     
-                /* see if we can patch the calling TB. */
+                /* see if we can patch the calling TB. When the TB
+                   spans two pages, we cannot safely do a direct
+                   jump. */
                 {
-                    if (T0 != 0
+                    if (T0 != 0 &&
+                        tb->page_addr[1] == -1
 #if defined(TARGET_I386) && defined(USE_CODE_COPY)
                     && (tb->cflags & CF_CODE_COPY) == 
                     (((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY)
@@ -699,7 +798,6 @@ int cpu_exec(CPUState *env1)
     EDI = saved_EDI;
 #endif
 #elif defined(TARGET_ARM)
-    env->cpsr = compute_cpsr();
     /* XXX: Save/restore host fpu exception state?.  */
 #elif defined(TARGET_SPARC)
 #if defined(reg_REGWPTR)
@@ -719,6 +817,8 @@ int cpu_exec(CPUState *env1)
     T2 = saved_T2;
 #endif
     env = saved_env;
+    /* fail safe : never use cpu_single_env outside cpu_exec() */
+    cpu_single_env = NULL; 
     return ret;
 }
 
@@ -827,7 +927,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
         /* we restore the process signal mask as the sigreturn should
            do it (XXX: use sigsetjmp) */
         sigprocmask(SIG_SETMASK, old_set, NULL);
-        raise_exception_err(EXCP0E_PAGE, env->error_code);
+        raise_exception_err(env->exception_index, env->error_code);
     } else {
         /* activate soft MMU for this block */
         env->hflags |= HF_SOFTMMU_MASK;
@@ -979,7 +1079,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
     }
 
     /* see if it is an MMU fault */
-    ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
+    ret = cpu_mips_handle_mmu_fault(env, address, is_write, 1, 0);
     if (ret < 0)
         return 0; /* not an MMU fault */
     if (ret == 0)
index 880baf1..9d28785 100644 (file)
@@ -56,6 +56,17 @@ enum bfd_architecture
 #define bfd_mach_m68030 5
 #define bfd_mach_m68040 6
 #define bfd_mach_m68060 7
+#define bfd_mach_cpu32  8
+#define bfd_mach_mcf5200  9
+#define bfd_mach_mcf5206e 10
+#define bfd_mach_mcf5307  11
+#define bfd_mach_mcf5407  12
+#define bfd_mach_mcf528x  13
+#define bfd_mach_mcfv4e   14
+#define bfd_mach_mcf521x   15
+#define bfd_mach_mcf5249   16
+#define bfd_mach_mcf547x   17
+#define bfd_mach_mcf548x   18
   bfd_arch_vax,        /* DEC Vax */   
   bfd_arch_i960,       /* Intel 960 */
      /* The order of the following is important.
@@ -417,6 +428,7 @@ extern int generic_symbol_at_address
   (INFO).insn_info_valid = 0
 
 #define _(x) x
+#define ATTRIBUTE_UNUSED __attribute__((unused))
 
 /* from libbfd */
 
@@ -425,5 +437,6 @@ bfd_vma bfd_getb32 (const bfd_byte *addr);
 bfd_vma bfd_getl16 (const bfd_byte *addr);
 bfd_vma bfd_getb16 (const bfd_byte *addr);
 typedef enum bfd_boolean {false, true} boolean;
+typedef boolean bfd_boolean;
 
 #endif /* ! defined (DIS_ASM_H) */
index aea8cfe..f8281b5 100644 (file)
@@ -138,6 +138,7 @@ print_insn_thumb1(bfd_vma pc, disassemble_info *info)
    values:
     i386 - nonzero means 16 bit code
     arm  - nonzero means thumb code 
+    ppc  - nonzero means little endian
     other targets - unused
  */
 void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
@@ -177,7 +178,7 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
     disasm_info.mach = bfd_mach_sparc_v9b;
 #endif    
 #elif defined(TARGET_PPC)
-    if (cpu_single_env->msr[MSR_LE])
+    if (flags)
         disasm_info.endian = BFD_ENDIAN_LITTLE;
 #ifdef TARGET_PPC64
     disasm_info.mach = bfd_mach_ppc64;
@@ -186,8 +187,14 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
 #endif
     print_insn = print_insn_ppc;
 #elif defined(TARGET_MIPS)
+#ifdef TARGET_WORDS_BIGENDIAN
     print_insn = print_insn_big_mips;
 #else
+    print_insn = print_insn_little_mips;
+#endif
+#elif defined(TARGET_M68K)
+    print_insn = print_insn_m68k;
+#else
     fprintf(out, "0x" TARGET_FMT_lx
            ": Asm output not supported on this arch\n", code);
     return;
@@ -251,6 +258,8 @@ void disas(FILE *out, void *code, unsigned long size)
     print_insn = print_insn_big_mips;
 #elif defined(__MIPSEL__)
     print_insn = print_insn_little_mips;
+#elif defined(__m68k__)
+    print_insn = print_insn_m68k;
 #else
     fprintf(out, "0x%lx: Asm output not supported on this arch\n",
            (long) code);
@@ -279,6 +288,7 @@ const char *lookup_symbol(target_ulong orig_addr)
     /* Hack, because we know this is x86. */
     Elf32_Sym *sym;
     struct syminfo *s;
+    target_ulong addr;
     
     for (s = syminfos; s; s = s->next) {
        sym = s->disas_symtab;
@@ -290,8 +300,13 @@ const char *lookup_symbol(target_ulong orig_addr)
            if (ELF_ST_TYPE(sym[i].st_info) != STT_FUNC)
                continue;
 
-           if (orig_addr >= sym[i].st_value
-               && orig_addr < sym[i].st_value + sym[i].st_size)
+           addr = sym[i].st_value;
+#ifdef TARGET_ARM
+            /* The bottom address bit marks a Thumb symbol.  */
+            addr &= ~(target_ulong)1;
+#endif
+           if (orig_addr >= addr
+               && orig_addr < addr + sym[i].st_size)
                return s->disas_strtab + sym[i].st_name;
        }
     }
@@ -304,6 +319,7 @@ void term_vprintf(const char *fmt, va_list ap);
 void term_printf(const char *fmt, ...);
 
 static int monitor_disas_is_physical;
+static CPUState *monitor_disas_env;
 
 static int
 monitor_read_memory (memaddr, myaddr, length, info)
@@ -315,7 +331,7 @@ monitor_read_memory (memaddr, myaddr, length, info)
     if (monitor_disas_is_physical) {
         cpu_physical_memory_rw(memaddr, myaddr, length, 0);
     } else {
-        cpu_memory_rw_debug(cpu_single_env, memaddr,myaddr, length, 0);
+        cpu_memory_rw_debug(monitor_disas_env, memaddr,myaddr, length, 0);
     }
     return 0;
 }
@@ -329,7 +345,8 @@ static int monitor_fprintf(FILE *stream, const char *fmt, ...)
     return 0;
 }
 
-void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
+void monitor_disas(CPUState *env,
+                   target_ulong pc, int nb_insn, int is_physical, int flags)
 {
     int count, i;
     struct disassemble_info disasm_info;
@@ -337,6 +354,7 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
 
     INIT_DISASSEMBLE_INFO(disasm_info, NULL, monitor_fprintf);
 
+    monitor_disas_env = env;
     monitor_disas_is_physical = is_physical;
     disasm_info.read_memory_func = monitor_read_memory;
 
@@ -367,8 +385,14 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
 #endif
     print_insn = print_insn_ppc;
 #elif defined(TARGET_MIPS)
+#ifdef TARGET_WORDS_BIGENDIAN
     print_insn = print_insn_big_mips;
 #else
+    print_insn = print_insn_little_mips;
+#endif
+#elif defined(TARGET_M68K)
+    print_insn = print_insn_m68k;
+#else
     term_printf("0x" TARGET_FMT_lx
                ": Asm output not supported on this arch\n", pc);
     return;
index 32da4eb..ee0a79c 100644 (file)
@@ -4,7 +4,8 @@
 /* Disassemble this for me please... (debugging). */
 void disas(FILE *out, void *code, unsigned long size);
 void target_disas(FILE *out, target_ulong code, target_ulong size, int flags);
-void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags);
+void monitor_disas(CPUState *env,
+                   target_ulong pc, int nb_insn, int is_physical, int flags);
 
 /* Look up symbol for debugging purpose.  Returns "" if unknown. */
 const char *lookup_symbol(target_ulong orig_addr);
index 5db83d3..58debaa 100644 (file)
@@ -62,6 +62,7 @@ extern target_ulong gen_opc_npc[OPC_BUF_SIZE];
 extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
 extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
 extern target_ulong gen_opc_jump_pc[2];
+extern uint32_t gen_opc_hflags[OPC_BUF_SIZE];
 
 typedef void (GenOpFunc)(void);
 typedef void (GenOpFunc1)(long);
@@ -91,23 +92,28 @@ 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(void);
+void cpu_exec_init(CPUState *env);
 int page_unprotect(unsigned long address, unsigned long pc, void *puc);
 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(CPUState *env, target_ulong vaddr, 
-                 target_phys_addr_t paddr, int prot, 
-                 int is_user, int is_softmmu);
+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, 
+                               int is_user, int is_softmmu)
+{
+    if (prot & PAGE_READ)
+        prot |= PAGE_EXEC;
+    return tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
+}
 
 #define CODE_GEN_MAX_SIZE        65536
 #define CODE_GEN_ALIGN           16 /* must be >= of the size of a icache line */
 
-#define CODE_GEN_HASH_BITS     15
-#define CODE_GEN_HASH_SIZE     (1 << CODE_GEN_HASH_BITS)
-
 #define CODE_GEN_PHYS_HASH_BITS     15
 #define CODE_GEN_PHYS_HASH_SIZE     (1 << CODE_GEN_PHYS_HASH_BITS)
 
@@ -167,7 +173,6 @@ typedef struct TranslationBlock {
 #define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */
 
     uint8_t *tc_ptr;    /* pointer to the translated code */
-    struct TranslationBlock *hash_next; /* next matching tb for virtual address */
     /* next matching tb for physical address. */
     struct TranslationBlock *phys_hash_next; 
     /* first and second physical page containing code. The lower bit
@@ -191,9 +196,9 @@ typedef struct TranslationBlock {
     struct TranslationBlock *jmp_first;
 } TranslationBlock;
 
-static inline unsigned int tb_hash_func(target_ulong pc)
+static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc)
 {
-    return pc & (CODE_GEN_HASH_SIZE - 1);
+    return (pc ^ (pc >> TB_JMP_CACHE_BITS)) & (TB_JMP_CACHE_SIZE - 1);
 }
 
 static inline unsigned int tb_phys_hash_func(unsigned long pc)
@@ -203,41 +208,14 @@ static inline unsigned int tb_phys_hash_func(unsigned long pc)
 
 TranslationBlock *tb_alloc(target_ulong pc);
 void tb_flush(CPUState *env);
-void tb_link(TranslationBlock *tb);
 void tb_link_phys(TranslationBlock *tb, 
                   target_ulong phys_pc, target_ulong phys_page2);
 
-extern TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
 extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
 
 extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
 extern uint8_t *code_gen_ptr;
 
-/* find a translation block in the translation cache. If not found,
-   return NULL and the pointer to the last element of the list in pptb */
-static inline TranslationBlock *tb_find(TranslationBlock ***pptb,
-                                        target_ulong pc, 
-                                        target_ulong cs_base,
-                                        unsigned int flags)
-{
-    TranslationBlock **ptb, *tb;
-    unsigned int h;
-    h = tb_hash_func(pc);
-    ptb = &tb_hash[h];
-    for(;;) {
-        tb = *ptb;
-        if (!tb)
-            break;
-        if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
-            return tb;
-        ptb = &tb->hash_next;
-    }
-    *pptb = ptb;
-    return NULL;
-}
-
-
 #if defined(USE_DIRECT_JUMP)
 
 #if defined(__powerpc__)
@@ -365,15 +343,6 @@ dummy_label ## n: ;\
 
 #endif
 
-/* XXX: will be suppressed */
-#define JUMP_TB(opname, tbparam, n, eip)\
-do {\
-    GOTO_TB(opname, tbparam, n);\
-    T0 = (long)(tbparam) + (n);\
-    EIP = (int32_t)eip;\
-    EXIT_TB();\
-} while (0)
-
 extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
 extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
 extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
@@ -589,18 +558,20 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
     is_user = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
 #elif defined (TARGET_SPARC)
     is_user = (env->psrs == 0);
+#elif defined (TARGET_ARM)
+    is_user = ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR);
 #else
-#error "Unimplemented !"
+#error unimplemented CPU
 #endif
-    if (__builtin_expect(env->tlb_read[is_user][index].address != 
+    if (__builtin_expect(env->tlb_table[is_user][index].addr_code != 
                          (addr & TARGET_PAGE_MASK), 0)) {
         ldub_code(addr);
     }
-    pd = env->tlb_read[is_user][index].address & ~TARGET_PAGE_MASK;
+    pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK;
     if (pd > IO_MEM_ROM) {
         cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x%08lx\n", addr);
     }
-    return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base;
+    return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base;
 }
 #endif
 
index 11a3a64..3028a52 100644 (file)
@@ -61,7 +61,6 @@
 #endif
 
 TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
-TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
 TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
 int nb_tbs;
 /* any access to the tbs or the page table must use this lock */
@@ -75,6 +74,11 @@ int phys_ram_fd;
 uint8_t *phys_ram_base;
 uint8_t *phys_ram_dirty;
 
+CPUState *first_cpu;
+/* current CPU in the current thread. It is only valid inside
+   cpu_exec() */
+CPUState *cpu_single_env; 
+
 typedef struct PageDesc {
     /* list of TBs intersecting this ram page */
     TranslationBlock *first_tb;
@@ -92,20 +96,6 @@ typedef struct PhysPageDesc {
     uint32_t phys_offset;
 } PhysPageDesc;
 
-/* Note: the VirtPage handling is absolete and will be suppressed
-   ASAP */
-typedef struct VirtPageDesc {
-    /* physical address of code page. It is valid only if 'valid_tag'
-       matches 'virt_valid_tag' */ 
-    target_ulong phys_addr; 
-    unsigned int valid_tag;
-#if !defined(CONFIG_SOFTMMU)
-    /* original page access rights. It is valid only if 'valid_tag'
-       matches 'virt_valid_tag' */
-    unsigned int prot;
-#endif
-} VirtPageDesc;
-
 #define L2_BITS 10
 #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
 
@@ -123,17 +113,6 @@ unsigned long qemu_host_page_mask;
 static PageDesc *l1_map[L1_SIZE];
 PhysPageDesc **l1_phys_map;
 
-#if !defined(CONFIG_USER_ONLY)
-#if TARGET_LONG_BITS > 32
-#define VIRT_L_BITS 9
-#define VIRT_L_SIZE (1 << VIRT_L_BITS)
-static void *l1_virt_map[VIRT_L_SIZE];
-#else
-static VirtPageDesc *l1_virt_map[L1_SIZE];
-#endif
-static unsigned int virt_valid_tag;
-#endif
-
 /* io memory support */
 CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
 CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
@@ -190,9 +169,6 @@ static void page_init(void)
     while ((1 << qemu_host_page_bits) < qemu_host_page_size)
         qemu_host_page_bits++;
     qemu_host_page_mask = ~(qemu_host_page_size - 1);
-#if !defined(CONFIG_USER_ONLY)
-    virt_valid_tag = 1;
-#endif
     l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
     memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
 }
@@ -262,133 +238,30 @@ static inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
 }
 
 #if !defined(CONFIG_USER_ONLY)
-static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr, 
-                             target_ulong vaddr);
+static void tlb_protect_code(ram_addr_t ram_addr);
 static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, 
                                     target_ulong vaddr);
-
-static VirtPageDesc *virt_page_find_alloc(target_ulong index, int alloc)
-{
-#if TARGET_LONG_BITS > 32
-    void **p, **lp;
-
-    p = l1_virt_map;
-    lp = p + ((index >> (5 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
-    p = *lp;
-    if (!p) {
-        if (!alloc)
-            return NULL;
-        p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
-        *lp = p;
-    }
-    lp = p + ((index >> (4 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
-    p = *lp;
-    if (!p) {
-        if (!alloc)
-            return NULL;
-        p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
-        *lp = p;
-    }
-    lp = p + ((index >> (3 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
-    p = *lp;
-    if (!p) {
-        if (!alloc)
-            return NULL;
-        p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
-        *lp = p;
-    }
-    lp = p + ((index >> (2 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
-    p = *lp;
-    if (!p) {
-        if (!alloc)
-            return NULL;
-        p = qemu_mallocz(sizeof(void *) * VIRT_L_SIZE);
-        *lp = p;
-    }
-    lp = p + ((index >> (1 * VIRT_L_BITS)) & (VIRT_L_SIZE - 1));
-    p = *lp;
-    if (!p) {
-        if (!alloc)
-            return NULL;
-        p = qemu_mallocz(sizeof(VirtPageDesc) * VIRT_L_SIZE);
-        *lp = p;
-    }
-    return ((VirtPageDesc *)p) + (index & (VIRT_L_SIZE - 1));
-#else
-    VirtPageDesc *p, **lp;
-
-    lp = &l1_virt_map[index >> L2_BITS];
-    p = *lp;
-    if (!p) {
-        /* allocate if not found */
-        if (!alloc)
-            return NULL;
-        p = qemu_mallocz(sizeof(VirtPageDesc) * L2_SIZE);
-        *lp = p;
-    }
-    return p + (index & (L2_SIZE - 1));
-#endif
-}
-
-static inline VirtPageDesc *virt_page_find(target_ulong index)
-{
-    return virt_page_find_alloc(index, 0);
-}
-
-#if TARGET_LONG_BITS > 32
-static void virt_page_flush_internal(void **p, int level)
-{
-    int i; 
-    if (level == 0) {
-        VirtPageDesc *q = (VirtPageDesc *)p;
-        for(i = 0; i < VIRT_L_SIZE; i++)
-            q[i].valid_tag = 0;
-    } else {
-        level--;
-        for(i = 0; i < VIRT_L_SIZE; i++) {
-            if (p[i])
-                virt_page_flush_internal(p[i], level);
-        }
-    }
-}
 #endif
 
-static void virt_page_flush(void)
+void cpu_exec_init(CPUState *env)
 {
-    virt_valid_tag++;
+    CPUState **penv;
+    int cpu_index;
 
-    if (virt_valid_tag == 0) {
-        virt_valid_tag = 1;
-#if TARGET_LONG_BITS > 32
-        virt_page_flush_internal(l1_virt_map, 5);
-#else
-        {
-            int i, j;
-            VirtPageDesc *p;
-            for(i = 0; i < L1_SIZE; i++) {
-                p = l1_virt_map[i];
-                if (p) {
-                    for(j = 0; j < L2_SIZE; j++)
-                        p[j].valid_tag = 0;
-                }
-            }
-        }
-#endif
-    }
-}
-#else
-static void virt_page_flush(void)
-{
-}
-#endif
-
-void cpu_exec_init(void)
-{
     if (!code_gen_ptr) {
         code_gen_ptr = code_gen_buffer;
         page_init();
         io_mem_init();
     }
+    env->next_cpu = NULL;
+    penv = &first_cpu;
+    cpu_index = 0;
+    while (*penv != NULL) {
+        penv = (CPUState **)&(*penv)->next_cpu;
+        cpu_index++;
+    }
+    env->cpu_index = cpu_index;
+    *penv = env;
 }
 
 static inline void invalidate_page_bitmap(PageDesc *p)
@@ -420,8 +293,9 @@ static void page_flush_tb(void)
 
 /* flush all the translation blocks */
 /* XXX: tb_flush is currently not thread safe */
-void tb_flush(CPUState *env)
+void tb_flush(CPUState *env1)
 {
+    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, 
@@ -429,8 +303,10 @@ void tb_flush(CPUState *env)
            nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
 #endif
     nb_tbs = 0;
-    memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
-    virt_page_flush();
+    
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
+    }
 
     memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
     page_flush_tb();
@@ -566,27 +442,39 @@ static inline void tb_reset_jump(TranslationBlock *tb, int n)
     tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
 }
 
-static inline void tb_invalidate(TranslationBlock *tb)
+static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
 {
+    CPUState *env;
+    PageDesc *p;
     unsigned int h, n1;
-    TranslationBlock *tb1, *tb2, **ptb;
+    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, 
+              offsetof(TranslationBlock, phys_hash_next));
+
+    /* remove the TB from the page list */
+    if (tb->page_addr[0] != page_addr) {
+        p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
+        tb_page_remove(&p->first_tb, tb);
+        invalidate_page_bitmap(p);
+    }
+    if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
+        p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
+        tb_page_remove(&p->first_tb, tb);
+        invalidate_page_bitmap(p);
+    }
+
     tb_invalidated_flag = 1;
 
     /* remove the TB from the hash list */
-    h = tb_hash_func(tb->pc);
-    ptb = &tb_hash[h];
-    for(;;) {
-        tb1 = *ptb;
-        /* NOTE: the TB is not necessarily linked in the hash. It
-           indicates that it is not currently used */
-        if (tb1 == NULL)
-            return;
-        if (tb1 == tb) {
-            *ptb = tb1->hash_next;
-            break;
-        }
-        ptb = &tb1->hash_next;
+    h = tb_jmp_cache_hash_func(tb->pc);
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        if (env->tb_jmp_cache[h] == tb)
+            env->tb_jmp_cache[h] = NULL;
     }
 
     /* suppress this TB from the two jump lists */
@@ -606,33 +494,7 @@ static inline void tb_invalidate(TranslationBlock *tb)
         tb1 = tb2;
     }
     tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
-}
-
-static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr)
-{
-    PageDesc *p;
-    unsigned int h;
-    target_ulong phys_pc;
-    
-    /* 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, 
-              offsetof(TranslationBlock, phys_hash_next));
 
-    /* remove the TB from the page list */
-    if (tb->page_addr[0] != page_addr) {
-        p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
-        tb_page_remove(&p->first_tb, tb);
-        invalidate_page_bitmap(p);
-    }
-    if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
-        p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
-        tb_page_remove(&p->first_tb, tb);
-        invalidate_page_bitmap(p);
-    }
-
-    tb_invalidate(tb);
     tb_phys_invalidate_count++;
 }
 
@@ -810,12 +672,19 @@ void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
 #endif
             }
 #endif /* TARGET_HAS_PRECISE_SMC */
-            saved_tb = env->current_tb;
-            env->current_tb = NULL;
+            /* we need to do that to handle the case where a signal
+               occurs while doing tb_phys_invalidate() */
+            saved_tb = NULL;
+            if (env) {
+                saved_tb = env->current_tb;
+                env->current_tb = NULL;
+            }
             tb_phys_invalidate(tb, -1);
-            env->current_tb = saved_tb;
-            if (env->interrupt_request && env->current_tb)
-                cpu_interrupt(env, env->interrupt_request);
+            if (env) {
+                env->current_tb = saved_tb;
+                if (env->interrupt_request && env->current_tb)
+                    cpu_interrupt(env, env->interrupt_request);
+            }
         }
         tb = tb_next;
     }
@@ -980,10 +849,7 @@ static inline void tb_alloc_page(TranslationBlock *tb,
        protected. So we handle the case where only the first TB is
        allocated in a physical page */
     if (!last_first_tb) {
-        target_ulong virt_addr;
-
-        virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS);
-        tlb_protect_code(cpu_single_env, page_addr, virt_addr);
+        tlb_protect_code(page_addr);
     }
 #endif
 
@@ -1025,57 +891,6 @@ void tb_link_phys(TranslationBlock *tb,
         tb_alloc_page(tb, 1, phys_page2);
     else
         tb->page_addr[1] = -1;
-#ifdef DEBUG_TB_CHECK
-    tb_page_check();
-#endif
-}
-
-/* link the tb with the other TBs */
-void tb_link(TranslationBlock *tb)
-{
-#if !defined(CONFIG_USER_ONLY)
-    {
-        VirtPageDesc *vp;
-        target_ulong addr;
-        
-        /* save the code memory mappings (needed to invalidate the code) */
-        addr = tb->pc & TARGET_PAGE_MASK;
-        vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
-#ifdef DEBUG_TLB_CHECK 
-        if (vp->valid_tag == virt_valid_tag &&
-            vp->phys_addr != tb->page_addr[0]) {
-            printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
-                   addr, tb->page_addr[0], vp->phys_addr);
-        }
-#endif
-        vp->phys_addr = tb->page_addr[0];
-        if (vp->valid_tag != virt_valid_tag) {
-            vp->valid_tag = virt_valid_tag;
-#if !defined(CONFIG_SOFTMMU)
-            vp->prot = 0;
-#endif
-        }
-        
-        if (tb->page_addr[1] != -1) {
-            addr += TARGET_PAGE_SIZE;
-            vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
-#ifdef DEBUG_TLB_CHECK 
-            if (vp->valid_tag == virt_valid_tag &&
-                vp->phys_addr != tb->page_addr[1]) { 
-                printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n",
-                       addr, tb->page_addr[1], vp->phys_addr);
-            }
-#endif
-            vp->phys_addr = tb->page_addr[1];
-            if (vp->valid_tag != virt_valid_tag) {
-                vp->valid_tag = virt_valid_tag;
-#if !defined(CONFIG_SOFTMMU)
-                vp->prot = 0;
-#endif
-            }
-        }
-    }
-#endif
 
     tb->jmp_first = (TranslationBlock *)((long)tb | 2);
     tb->jmp_next[0] = NULL;
@@ -1091,6 +906,10 @@ void tb_link(TranslationBlock *tb)
         tb_reset_jump(tb, 0);
     if (tb->tb_next_offset[1] != 0xffff)
         tb_reset_jump(tb, 1);
+
+#ifdef DEBUG_TB_CHECK
+    tb_page_check();
+#endif
 }
 
 /* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
@@ -1390,14 +1209,15 @@ void tlb_flush(CPUState *env, int flush_global)
     env->current_tb = NULL;
 
     for(i = 0; i < CPU_TLB_SIZE; i++) {
-        env->tlb_read[0][i].address = -1;
-        env->tlb_write[0][i].address = -1;
-        env->tlb_read[1][i].address = -1;
-        env->tlb_write[1][i].address = -1;
+        env->tlb_table[0][i].addr_read = -1;
+        env->tlb_table[0][i].addr_write = -1;
+        env->tlb_table[0][i].addr_code = -1;
+        env->tlb_table[1][i].addr_read = -1;
+        env->tlb_table[1][i].addr_write = -1;
+        env->tlb_table[1][i].addr_code = -1;
     }
 
-    virt_page_flush();
-    memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
+    memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
 
 #if !defined(CONFIG_SOFTMMU)
     munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
@@ -1412,16 +1232,21 @@ void tlb_flush(CPUState *env, int flush_global)
 
 static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
 {
-    if (addr == (tlb_entry->address & 
-                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
-        tlb_entry->address = -1;
+    if (addr == (tlb_entry->addr_read & 
+                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
+        addr == (tlb_entry->addr_write & 
+                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
+        addr == (tlb_entry->addr_code & 
+                 (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+        tlb_entry->addr_read = -1;
+        tlb_entry->addr_write = -1;
+        tlb_entry->addr_code = -1;
+    }
 }
 
 void tlb_flush_page(CPUState *env, target_ulong addr)
 {
-    int i, n;
-    VirtPageDesc *vp;
-    PageDesc *p;
+    int i;
     TranslationBlock *tb;
 
 #if defined(DEBUG_TLB)
@@ -1433,31 +1258,16 @@ void tlb_flush_page(CPUState *env, target_ulong addr)
 
     addr &= TARGET_PAGE_MASK;
     i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
-    tlb_flush_entry(&env->tlb_read[0][i], addr);
-    tlb_flush_entry(&env->tlb_write[0][i], addr);
-    tlb_flush_entry(&env->tlb_read[1][i], addr);
-    tlb_flush_entry(&env->tlb_write[1][i], addr);
-
-    /* remove from the virtual pc hash table all the TB at this
-       virtual address */
-    
-    vp = virt_page_find(addr >> TARGET_PAGE_BITS);
-    if (vp && vp->valid_tag == virt_valid_tag) {
-        p = page_find(vp->phys_addr >> TARGET_PAGE_BITS);
-        if (p) {
-            /* we remove all the links to the TBs in this virtual page */
-            tb = p->first_tb;
-            while (tb != NULL) {
-                n = (long)tb & 3;
-                tb = (TranslationBlock *)((long)tb & ~3);
-                if ((tb->pc & TARGET_PAGE_MASK) == addr ||
-                    ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr) {
-                    tb_invalidate(tb);
-                }
-                tb = tb->page_next[n];
-            }
+    tlb_flush_entry(&env->tlb_table[0][i], addr);
+    tlb_flush_entry(&env->tlb_table[1][i], addr);
+
+    for(i = 0; i < TB_JMP_CACHE_SIZE; i++) {
+        tb = env->tb_jmp_cache[i];
+        if (tb && 
+            ((tb->pc & TARGET_PAGE_MASK) == addr ||
+             ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr)) {
+            env->tb_jmp_cache[i] = NULL;
         }
-        vp->valid_tag = 0;
     }
 
 #if !defined(CONFIG_SOFTMMU)
@@ -1471,40 +1281,13 @@ void tlb_flush_page(CPUState *env, target_ulong addr)
 #endif
 }
 
-static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr)
-{
-    if (addr == (tlb_entry->address & 
-                 (TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
-        (tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
-        tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
-    }
-}
-
 /* update the TLBs so that writes to code in the virtual page 'addr'
    can be detected */
-static void tlb_protect_code(CPUState *env, ram_addr_t ram_addr, 
-                             target_ulong vaddr)
+static void tlb_protect_code(ram_addr_t ram_addr)
 {
-    int i;
-
-    vaddr &= TARGET_PAGE_MASK;
-    i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
-    tlb_protect_code1(&env->tlb_write[0][i], vaddr);
-    tlb_protect_code1(&env->tlb_write[1][i], vaddr);
-
-#ifdef USE_KQEMU
-    if (env->kqemu_enabled) {
-        kqemu_set_notdirty(env, ram_addr);
-    }
-#endif
-    phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] &= ~CODE_DIRTY_FLAG;
-    
-#if !defined(CONFIG_SOFTMMU)
-    /* NOTE: as we generated the code for this page, it is already at
-       least readable */
-    if (vaddr < MMAP_AREA_END)
-        mprotect((void *)vaddr, TARGET_PAGE_SIZE, PROT_READ);
-#endif
+    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
@@ -1519,10 +1302,10 @@ static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
                                          unsigned long start, unsigned long length)
 {
     unsigned long addr;
-    if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
-        addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
+    if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
+        addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
         if ((addr - start) < length) {
-            tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
+            tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
         }
     }
 }
@@ -1542,8 +1325,9 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
     if (length == 0)
         return;
     len = length >> TARGET_PAGE_BITS;
-    env = cpu_single_env;
 #ifdef USE_KQEMU
+    /* XXX: should not depend on cpu context */
+    env = first_cpu;
     if (env->kqemu_enabled) {
         ram_addr_t addr;
         addr = start;
@@ -1561,10 +1345,12 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
     /* we modify the TLB cache so that the dirty bit will be set again
        when accessing the range */
     start1 = start + (unsigned long)phys_ram_base;
-    for(i = 0; i < CPU_TLB_SIZE; i++)
-        tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length);
-    for(i = 0; i < CPU_TLB_SIZE; i++)
-        tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length);
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        for(i = 0; i < CPU_TLB_SIZE; i++)
+            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 !defined(CONFIG_SOFTMMU)
     /* XXX: this is expensive */
@@ -1599,11 +1385,11 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
 {
     ram_addr_t ram_addr;
 
-    if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
-        ram_addr = (tlb_entry->address & TARGET_PAGE_MASK) + 
+    if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
+        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->address |= IO_MEM_NOTDIRTY;
+            tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
         }
     }
 }
@@ -1613,43 +1399,43 @@ void cpu_tlb_update_dirty(CPUState *env)
 {
     int i;
     for(i = 0; i < CPU_TLB_SIZE; i++)
-        tlb_update_dirty(&env->tlb_write[0][i]);
+        tlb_update_dirty(&env->tlb_table[0][i]);
     for(i = 0; i < CPU_TLB_SIZE; i++)
-        tlb_update_dirty(&env->tlb_write[1][i]);
+        tlb_update_dirty(&env->tlb_table[1][i]);
 }
 
 static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, 
                                   unsigned long start)
 {
     unsigned long addr;
-    if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
-        addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend;
+    if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) {
+        addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
         if (addr == start) {
-            tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM;
+            tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM;
         }
     }
 }
 
 /* update the TLB corresponding to virtual page vaddr and phys addr
    addr so that it is no longer dirty */
-static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
+static inline void tlb_set_dirty(CPUState *env,
+                                 unsigned long addr, target_ulong vaddr)
 {
-    CPUState *env = cpu_single_env;
     int i;
 
     addr &= TARGET_PAGE_MASK;
     i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
-    tlb_set_dirty1(&env->tlb_write[0][i], addr);
-    tlb_set_dirty1(&env->tlb_write[1][i], addr);
+    tlb_set_dirty1(&env->tlb_table[0][i], addr);
+    tlb_set_dirty1(&env->tlb_table[1][i], addr);
 }
 
 /* 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(CPUState *env, target_ulong vaddr, 
-                 target_phys_addr_t paddr, int prot, 
-                 int is_user, int is_softmmu)
+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;
     unsigned long pd;
@@ -1657,6 +1443,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
     target_ulong address;
     target_phys_addr_t addend;
     int ret;
+    CPUTLBEntry *te;
 
     p = phys_page_find(paddr >> TARGET_PAGE_BITS);
     if (!p) {
@@ -1666,7 +1453,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
     }
 #if defined(DEBUG_TLB)
     printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d smmu=%d pd=0x%08lx\n",
-           vaddr, paddr, prot, is_user, is_softmmu, pd);
+           vaddr, (int)paddr, prot, is_user, is_softmmu, pd);
 #endif
 
     ret = 0;
@@ -1686,29 +1473,30 @@ int tlb_set_page(CPUState *env, target_ulong vaddr,
         
         index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
         addend -= vaddr;
+        te = &env->tlb_table[is_user][index];
+        te->addend = addend;
         if (prot & PAGE_READ) {
-            env->tlb_read[is_user][index].address = address;
-            env->tlb_read[is_user][index].addend = addend;
+            te->addr_read = address;
+        } else {
+            te->addr_read = -1;
+        }
+        if (prot & PAGE_EXEC) {
+            te->addr_code = address;
         } else {
-            env->tlb_read[is_user][index].address = -1;
-            env->tlb_read[is_user][index].addend = -1;
+            te->addr_code = -1;
         }
         if (prot & PAGE_WRITE) {
             if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) {
                 /* ROM: access is ignored (same as unassigned) */
-                env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
-                env->tlb_write[is_user][index].addend = addend;
+                te->addr_write = vaddr | IO_MEM_ROM;
             } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && 
                        !cpu_physical_memory_is_dirty(pd)) {
-                env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY;
-                env->tlb_write[is_user][index].addend = addend;
+                te->addr_write = vaddr | IO_MEM_NOTDIRTY;
             } else {
-                env->tlb_write[is_user][index].address = address;
-                env->tlb_write[is_user][index].addend = addend;
+                te->addr_write = address;
             }
         } else {
-            env->tlb_write[is_user][index].address = -1;
-            env->tlb_write[is_user][index].addend = -1;
+            te->addr_write = -1;
         }
     }
 #if !defined(CONFIG_SOFTMMU)
@@ -1807,9 +1595,9 @@ void tlb_flush_page(CPUState *env, target_ulong addr)
 {
 }
 
-int tlb_set_page(CPUState *env, target_ulong vaddr, 
-                 target_phys_addr_t paddr, int prot, 
-                 int is_user, int is_softmmu)
+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;
 }
@@ -1948,7 +1736,8 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size)
     }
 }
 
-static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
+static inline void tlb_set_dirty(CPUState *env,
+                                 unsigned long addr, target_ulong vaddr)
 {
 }
 #endif /* defined(CONFIG_USER_ONLY) */
@@ -2012,7 +1801,7 @@ static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t
     /* we remove the notdirty callback only if the code has been
        flushed */
     if (dirty_flags == 0xff)
-        tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
+        tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
 }
 
 static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
@@ -2033,7 +1822,7 @@ static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t
     /* we remove the notdirty callback only if the code has been
        flushed */
     if (dirty_flags == 0xff)
-        tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
+        tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
 }
 
 static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
@@ -2054,7 +1843,7 @@ static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t
     /* we remove the notdirty callback only if the code has been
        flushed */
     if (dirty_flags == 0xff)
-        tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
+        tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_write_vaddr);
 }
 
 static CPUReadMemoryFunc *error_mem_read[3] = {
@@ -2095,14 +1884,14 @@ int cpu_register_io_memory(int io_index,
     int i;
 
     if (io_index <= 0) {
-        if (io_index >= IO_MEM_NB_ENTRIES)
+        if (io_mem_nb >= IO_MEM_NB_ENTRIES)
             return -1;
         io_index = io_mem_nb++;
     } else {
         if (io_index >= IO_MEM_NB_ENTRIES)
             return -1;
     }
-    
+
     for(i = 0;i < 3; i++) {
         io_mem_read[io_index][i] = mem_read[i];
         io_mem_write[io_index][i] = mem_write[i];
@@ -2152,20 +1941,6 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
     }
 }
 
-/* never used */
-uint32_t ldl_phys(target_phys_addr_t addr)
-{
-    return 0;
-}
-
-void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
-{
-}
-
-void stl_phys(target_phys_addr_t addr, uint32_t val)
-{
-}
-
 #else
 void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 
                             int len, int is_write)
@@ -2192,6 +1967,8 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
         if (is_write) {
             if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
                 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+                /* XXX: could force cpu_single_env to NULL to avoid
+                   potential bugs */
                 if (l >= 4 && ((addr & 3) == 0)) {
                     /* 32 bit write access */
                     val = ldl_p(buf);
@@ -2284,6 +2061,57 @@ uint32_t ldl_phys(target_phys_addr_t addr)
     return val;
 }
 
+/* warning: addr must be aligned */
+uint64_t ldq_phys(target_phys_addr_t addr)
+{
+    int io_index;
+    uint8_t *ptr;
+    uint64_t val;
+    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_ROM) {
+        /* I/O case */
+        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+#ifdef TARGET_WORDS_BIGENDIAN
+        val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
+        val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
+#else
+        val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
+        val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
+#endif
+    } else {
+        /* RAM case */
+        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 
+            (addr & ~TARGET_PAGE_MASK);
+        val = ldq_p(ptr);
+    }
+    return val;
+}
+
+/* XXX: optimize */
+uint32_t ldub_phys(target_phys_addr_t addr)
+{
+    uint8_t val;
+    cpu_physical_memory_read(addr, &val, 1);
+    return val;
+}
+
+/* XXX: optimize */
+uint32_t lduw_phys(target_phys_addr_t addr)
+{
+    uint16_t val;
+    cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
+    return tswap16(val);
+}
+
 /* warning: addr must be aligned. The ram page is not masked as dirty
    and the code inside is not invalidated. It is useful if the dirty
    bits are used to track modified PTEs */
@@ -2345,6 +2173,27 @@ void stl_phys(target_phys_addr_t addr, uint32_t val)
     }
 }
 
+/* XXX: optimize */
+void stb_phys(target_phys_addr_t addr, uint32_t val)
+{
+    uint8_t v = val;
+    cpu_physical_memory_write(addr, &v, 1);
+}
+
+/* XXX: optimize */
+void stw_phys(target_phys_addr_t addr, uint32_t val)
+{
+    uint16_t v = tswap16(val);
+    cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
+}
+
+/* XXX: optimize */
+void stq_phys(target_phys_addr_t addr, uint64_t val)
+{
+    val = tswap64(val);
+    cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
+}
+
 #endif
 
 /* virtual memory access for debug */
index cbae320..5fdf800 100644 (file)
@@ -47,6 +47,7 @@ enum RSState {
 static int gdbserver_fd = -1;
 
 typedef struct GDBState {
+    CPUState *env; /* current CPU */
     enum RSState state; /* parsing state */
     int fd;
     char line_buf[4096];
@@ -297,7 +298,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
     int i;
 
     /* fill in g0..g7 */
-    for(i = 0; i < 7; i++) {
+    for(i = 0; i < 8; i++) {
         registers[i] = tswapl(env->gregs[i]);
     }
     /* fill in register window */
@@ -398,7 +399,7 @@ static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
     memset (ptr, 0, 8 * 12 + 4);
     ptr += 8 * 12 + 4;
     /* CPSR (4 bytes).  */
-    *(uint32_t *)ptr = tswapl (env->cpsr);
+    *(uint32_t *)ptr = tswapl (cpsr_read(env));
     ptr += 4;
 
     return ptr - mem_buf;
@@ -418,7 +419,73 @@ static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
       }
     /* Ignore FPA regs and scr.  */
     ptr += 8 * 12 + 4;
-    env->cpsr = tswapl(*(uint32_t *)ptr);
+    cpsr_write (env, tswapl(*(uint32_t *)ptr), 0xffffffff);
+}
+#elif defined (TARGET_MIPS)
+static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
+{
+    int i;
+    uint8_t *ptr;
+
+    ptr = mem_buf;
+    for (i = 0; i < 32; i++)
+      {
+        *(uint32_t *)ptr = tswapl(env->gpr[i]);
+        ptr += 4;
+      }
+
+    *(uint32_t *)ptr = tswapl(env->CP0_Status);
+    ptr += 4;
+
+    *(uint32_t *)ptr = tswapl(env->LO);
+    ptr += 4;
+
+    *(uint32_t *)ptr = tswapl(env->HI);
+    ptr += 4;
+
+    *(uint32_t *)ptr = tswapl(env->CP0_BadVAddr);
+    ptr += 4;
+
+    *(uint32_t *)ptr = tswapl(env->CP0_Cause);
+    ptr += 4;
+
+    *(uint32_t *)ptr = tswapl(env->PC);
+    ptr += 4;
+
+    /* 32 FP registers, fsr, fir, fp.  Not yet implemented.  */
+
+    return ptr - mem_buf;
+}
+
+static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
+{
+    int i;
+    uint8_t *ptr;
+
+    ptr = mem_buf;
+    for (i = 0; i < 32; i++)
+      {
+        env->gpr[i] = tswapl(*(uint32_t *)ptr);
+        ptr += 4;
+      }
+
+    env->CP0_Status = tswapl(*(uint32_t *)ptr);
+    ptr += 4;
+
+    env->LO = tswapl(*(uint32_t *)ptr);
+    ptr += 4;
+
+    env->HI = tswapl(*(uint32_t *)ptr);
+    ptr += 4;
+
+    env->CP0_BadVAddr = tswapl(*(uint32_t *)ptr);
+    ptr += 4;
+
+    env->CP0_Cause = tswapl(*(uint32_t *)ptr);
+    ptr += 4;
+
+    env->PC = tswapl(*(uint32_t *)ptr);
+    ptr += 4;
 }
 #else
 static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
@@ -462,6 +529,8 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
 #elif defined (TARGET_SPARC)
             env->pc = addr;
             env->npc = addr + 4;
+#elif defined (TARGET_ARM)
+            env->regs[15] = addr;
 #endif
         }
 #ifdef CONFIG_USER_ONLY
@@ -480,6 +549,8 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
 #elif defined (TARGET_SPARC)
             env->pc = addr;
             env->npc = addr + 4;
+#elif defined (TARGET_ARM)
+            env->regs[15] = addr;
 #endif
         }
         cpu_single_step(env, 1);
@@ -506,10 +577,12 @@ static int gdb_handle_packet(GDBState *s, CPUState *env, const char *line_buf)
         if (*p == ',')
             p++;
         len = strtoul(p, NULL, 16);
-        if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0)
-            memset(mem_buf, 0, len);
-        memtohex(buf, mem_buf, len);
-        put_packet(s, buf);
+        if (cpu_memory_rw_debug(env, addr, mem_buf, len, 0) != 0) {
+            put_packet (s, "E14");
+        } else {
+            memtohex(buf, mem_buf, len);
+            put_packet(s, buf);
+        }
         break;
     case 'M':
         addr = strtoul(p, (char **)&p, 16);
@@ -576,10 +649,10 @@ static void gdb_vm_stopped(void *opaque, int reason)
     int ret;
 
     /* disable single step if it was enable */
-    cpu_single_step(cpu_single_env, 0);
+    cpu_single_step(s->env, 0);
 
     if (reason == EXCP_DEBUG) {
-       tb_flush(cpu_single_env);
+       tb_flush(s->env);
         ret = SIGTRAP;
     }
     else
@@ -589,8 +662,9 @@ static void gdb_vm_stopped(void *opaque, int reason)
 }
 #endif
 
-static void gdb_read_byte(GDBState *s, CPUState *env, int ch)
+static void gdb_read_byte(GDBState *s, int ch)
 {
+    CPUState *env = s->env;
     int i, csum;
     char reply[1];
 
@@ -676,7 +750,7 @@ gdb_handlesig (CPUState *env, int sig)
           int i;
 
           for (i = 0; i < n; i++)
-            gdb_read_byte (s, env, buf[i]);
+            gdb_read_byte (s, buf[i]);
         }
       else if (n == 0 || errno != EAGAIN)
         {
@@ -704,30 +778,30 @@ void gdb_exit(CPUState *env, int code)
 }
 
 #else
-static int gdb_can_read(void *opaque)
-{
-    return 256;
-}
-
-static void gdb_read(void *opaque, const uint8_t *buf, int size)
+static void gdb_read(void *opaque)
 {
     GDBState *s = opaque;
-    int i;
+    int i, size;
+    uint8_t buf[4096];
+
+    size = read(s->fd, buf, sizeof(buf));
+    if (size < 0)
+        return;
     if (size == 0) {
         /* end of connection */
         qemu_del_vm_stop_handler(gdb_vm_stopped, s);
-        qemu_del_fd_read_handler(s->fd);
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
         qemu_free(s);
         vm_start();
     } else {
         for(i = 0; i < size; i++)
-            gdb_read_byte(s, cpu_single_env, buf[i]);
+            gdb_read_byte(s, buf[i]);
     }
 }
 
 #endif
 
-static void gdb_accept(void *opaque, const uint8_t *buf, int size)
+static void gdb_accept(void *opaque)
 {
     GDBState *s;
     struct sockaddr_in sockaddr;
@@ -759,6 +833,7 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size)
         return;
     }
 #endif
+    s->env = first_cpu; /* XXX: allow to change CPU */
     s->fd = fd;
 
     fcntl(fd, F_SETFL, O_NONBLOCK);
@@ -768,7 +843,7 @@ static void gdb_accept(void *opaque, const uint8_t *buf, int size)
     vm_stop(EXCP_INTERRUPT);
 
     /* start handling I/O */
-    qemu_add_fd_read_handler(s->fd, gdb_can_read, gdb_read, s);
+    qemu_set_fd_handler(s->fd, gdb_read, NULL, s);
     /* when the VM is stopped, the following callback is called */
     qemu_add_vm_stop_handler(gdb_vm_stopped, s);
 #endif
@@ -815,9 +890,9 @@ int gdbserver_start(int port)
         return -1;
     /* accept connections */
 #ifdef CONFIG_USER_ONLY
-    gdb_accept (NULL, NULL, 0);
+    gdb_accept (NULL);
 #else
-    qemu_add_fd_read_handler(gdbserver_fd, NULL, gdb_accept, NULL);
+    qemu_set_fd_handler(gdbserver_fd, gdb_accept, NULL, NULL);
 #endif
     return 0;
 }
index 939a7ed..f482d1f 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * QEMU Adlib emulation
- * 
- * Copyright (c) 2004 Vassili Karpov (malc)
- * 
+ * QEMU Proxy for OPL2/3 emulation by MAME team
+ *
+ * Copyright (c) 2004-2005 Vassili Karpov (malc)
+ *
  * 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
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include <assert.h>
 #include "vl.h"
 
+#define ADLIB_KILL_TIMERS 1
+
 #define dolog(...) AUD_log ("adlib", __VA_ARGS__)
 #ifdef DEBUG
 #define ldebug(...) dolog (__VA_ARGS__)
 #define ldebug(...)
 #endif
 
-#ifdef USE_YMF262
-#define HAS_YMF262 1
+#ifdef HAS_YMF262
 #include "ymf262.h"
-void YMF262UpdateOneQEMU(int which, INT16 *dst, int length);
+void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
 #define SHIFT 2
 #else
 #include "fmopl.h"
 #define SHIFT 1
 #endif
 
-#ifdef _WIN32
-#include <windows.h>
-#define small_delay() Sleep (1)
-#else
-#define small_delay() usleep (1)
-#endif
-
 #define IO_READ_PROTO(name) \
     uint32_t name (void *opaque, uint32_t nport)
 #define IO_WRITE_PROTO(name) \
@@ -58,23 +53,58 @@ static struct {
 } conf = {0x220, 44100};
 
 typedef struct {
+    QEMUSoundCard card;
+    int ticking[2];
     int enabled;
     int active;
-    int cparam;
-    int64_t ticks;
     int bufpos;
+#ifdef DEBUG
+    int64_t exp[2];
+#endif
     int16_t *mixbuf;
-    double interval;
-    QEMUTimer *ts, *opl_ts;
-    SWVoice *voice;
-    int left, pos, samples, bytes_per_second, old_free;
-    int refcount;
-#ifndef USE_YMF262
+    uint64_t dexp[2];
+    SWVoiceOut *voice;
+    int left, pos, samples;
+    QEMUAudioTimeStamp ats;
+#ifndef HAS_YMF262
     FM_OPL *opl;
 #endif
 } AdlibState;
 
-static AdlibState adlib;
+static AdlibState glob_adlib;
+
+static void adlib_stop_opl_timer (AdlibState *s, size_t n)
+{
+#ifdef HAS_YMF262
+    YMF262TimerOver (0, n);
+#else
+    OPLTimerOver (s->opl, n);
+#endif
+    s->ticking[n] = 0;
+}
+
+static void adlib_kill_timers (AdlibState *s)
+{
+    size_t i;
+
+    for (i = 0; i < 2; ++i) {
+        if (s->ticking[i]) {
+            uint64_t delta;
+
+            delta = AUD_get_elapsed_usec_out (s->voice, &s->ats);
+            ldebug (
+                "delta = %f dexp = %f expired => %d\n",
+                delta / 1000000.0,
+                s->dexp[i] / 1000000.0,
+                delta >= s->dexp[i]
+                );
+            if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) {
+                adlib_stop_opl_timer (s, i);
+                AUD_init_time_stamp_out (s->voice, &s->ats);
+            }
+        }
+    }
+}
 
 static IO_WRITE_PROTO(adlib_write)
 {
@@ -82,11 +112,12 @@ static IO_WRITE_PROTO(adlib_write)
     int a = nport & 3;
     int status;
 
-    s->ticks = qemu_get_clock (vm_clock);
     s->active = 1;
-    AUD_enable (s->voice, 1);
+    AUD_set_active_out (s->voice, 1);
 
-#ifdef USE_YMF262
+    adlib_kill_timers (s);
+
+#ifdef HAS_YMF262
     status = YMF262Write (0, a, val);
 #else
     status = OPLWrite (s->opl, a, val);
@@ -99,8 +130,9 @@ static IO_READ_PROTO(adlib_read)
     uint8_t data;
     int a = nport & 3;
 
-#ifdef USE_YMF262
-    (void) s;
+    adlib_kill_timers (s);
+
+#ifdef HAS_YMF262
     data = YMF262Read (0, a);
 #else
     data = OPLRead (s->opl, a);
@@ -108,119 +140,116 @@ static IO_READ_PROTO(adlib_read)
     return data;
 }
 
-static void OPL_timer (void *opaque)
+static void timer_handler (int c, double interval_Sec)
 {
-    AdlibState *s = opaque;
-#ifdef USE_YMF262
-    YMF262TimerOver (s->cparam >> 1, s->cparam & 1);
-#else
-    OPLTimerOver (s->opl, s->cparam);
+    AdlibState *s = &glob_adlib;
+    unsigned n = c & 1;
+#ifdef DEBUG
+    double interval;
+    int64_t exp;
 #endif
-    qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval);
-}
 
-static void YMF262TimerHandler (int c, double interval_Sec)
-{
-    AdlibState *s = &adlib;
     if (interval_Sec == 0.0) {
-        qemu_del_timer (s->opl_ts);
+        s->ticking[n] = 0;
         return;
     }
-    s->cparam = c;
-    s->interval = ticks_per_sec * interval_Sec;
-    qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval);
-    small_delay ();
+
+    s->ticking[n] = 1;
+#ifdef DEBUG
+    interval = ticks_per_sec * interval_Sec;
+    exp = qemu_get_clock (vm_clock) + interval;
+    s->exp[n] = exp;
+#endif
+
+    s->dexp[n] = interval_Sec * 1000000.0;
+    AUD_init_time_stamp_out (s->voice, &s->ats);
 }
 
 static int write_audio (AdlibState *s, int samples)
 {
     int net = 0;
-    int ss = samples;
+    int pos = s->pos;
+
     while (samples) {
-        int nbytes = samples << SHIFT;
-        int wbytes = AUD_write (s->voice,
-                                s->mixbuf + (s->pos << (SHIFT - 1)),
-                                nbytes);
-        int wsampl = wbytes >> SHIFT;
-        samples -= wsampl;
-        s->pos = (s->pos + wsampl) % s->samples;
-        net += wsampl;
-        if (!wbytes)
+        int nbytes, wbytes, wsampl;
+
+        nbytes = samples << SHIFT;
+        wbytes = AUD_write (
+            s->voice,
+            s->mixbuf + (pos << (SHIFT - 1)),
+            nbytes
+            );
+
+        if (wbytes) {
+            wsampl = wbytes >> SHIFT;
+
+            samples -= wsampl;
+            pos = (pos + wsampl) % s->samples;
+
+            net += wsampl;
+        }
+        else {
             break;
+        }
     }
-    if (net > ss) {
-        dolog ("WARNING: net > ss\n");
-    }
+
     return net;
 }
 
-static void timer (void *opaque)
+static void adlib_callback (void *opaque, int free)
 {
     AdlibState *s = opaque;
-    int elapsed, samples, net = 0;
-
-    if (s->refcount)
-        dolog ("refcount=%d\n", s->refcount);
-
-    s->refcount += 1;
-    if (!(s->active && s->enabled))
-        goto reset;
-
-    AUD_run ();
+    int samples, net = 0, to_play, written;
 
-    while (s->left) {
-        int written = write_audio (s, s->left);
-        net += written;
-        if (!written)
-            goto reset2;
-        s->left -= written;
+    samples = free >> SHIFT;
+    if (!(s->active && s->enabled) || !samples) {
+        return;
     }
-    s->pos = 0;
-
-    elapsed = AUD_calc_elapsed (s->voice);
-    if (!elapsed)
-        goto reset2;
 
-    /* elapsed = AUD_get_free (s->voice); */
-    samples = elapsed >> SHIFT;
-    if (!samples)
-        goto reset2;
+    to_play = audio_MIN (s->left, samples);
+    while (to_play) {
+        written = write_audio (s, to_play);
+
+        if (written) {
+            s->left -= written;
+            samples -= written;
+            to_play -= written;
+            s->pos = (s->pos + written) % s->samples;
+        }
+        else {
+            return;
+        }
+    }
 
     samples = audio_MIN (samples, s->samples - s->pos);
-    if (s->left)
-        dolog ("left=%d samples=%d elapsed=%d free=%d\n",
-               s->left, samples, elapsed, AUD_get_free (s->voice));
-
-    if (!samples)
-        goto reset2;
+    if (!samples) {
+        return;
+    }
 
-#ifdef USE_YMF262
+#ifdef HAS_YMF262
     YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
 #else
     YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
 #endif
 
     while (samples) {
-        int written = write_audio (s, samples);
-        net += written;
-        if (!written)
-            break;
-        samples -= written;
+        written = write_audio (s, samples);
+
+        if (written) {
+            net += written;
+            samples -= written;
+            s->pos = (s->pos + written) % s->samples;
+        }
+        else {
+            s->left = samples;
+            return;
+        }
     }
-    if (!samples)
-        s->pos = 0;
-    s->left = samples;
-
-reset2:
-    AUD_adjust (s->voice, net << SHIFT);
-reset:
-    qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + ticks_per_sec / 1024);
-    s->refcount -= 1;
 }
 
 static void Adlib_fini (AdlibState *s)
 {
-#ifdef USE_YMF262
+#ifdef HAS_YMF262
     YMF262Shutdown ();
 #else
     if (s->opl) {
@@ -229,77 +258,76 @@ static void Adlib_fini (AdlibState *s)
     }
 #endif
 
-    if (s->opl_ts)
-        qemu_free_timer (s->opl_ts);
-
-    if (s->ts)
-        qemu_free_timer (s->ts);
-
-#define maybe_free(p) if (p) qemu_free (p)
-    maybe_free (s->mixbuf);
-#undef maybe_free
+    if (s->mixbuf) {
+        qemu_free (s->mixbuf);
+    }
 
     s->active = 0;
     s->enabled = 0;
+    AUD_remove_card (&s->card);
 }
 
-void Adlib_init (void)
+int Adlib_init (AudioState *audio)
 {
-    AdlibState *s = &adlib;
+    AdlibState *s = &glob_adlib;
+    audsettings_t as;
 
-    memset (s, 0, sizeof (*s));
+    if (!audio) {
+        dolog ("No audio state\n");
+        return -1;
+    }
 
-#ifdef USE_YMF262
+#ifdef HAS_YMF262
     if (YMF262Init (1, 14318180, conf.freq)) {
         dolog ("YMF262Init %d failed\n", conf.freq);
-        return;
+        return -1;
     }
     else {
-        YMF262SetTimerHandler (0, YMF262TimerHandler, 0);
+        YMF262SetTimerHandler (0, timer_handler, 0);
         s->enabled = 1;
     }
 #else
     s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq);
     if (!s->opl) {
         dolog ("OPLCreate %d failed\n", conf.freq);
-        return;
+        return -1;
     }
     else {
-        OPLSetTimerHandler (s->opl, YMF262TimerHandler, 0);
+        OPLSetTimerHandler (s->opl, timer_handler, 0);
         s->enabled = 1;
     }
 #endif
 
-    s->opl_ts = qemu_new_timer (vm_clock, OPL_timer, s);
-    if (!s->opl_ts) {
-        dolog ("Can not get timer for adlib emulation\n");
-        Adlib_fini (s);
-        return;
-    }
-
-    s->ts = qemu_new_timer (vm_clock, timer, s);
-    if (!s->opl_ts) {
-        dolog ("Can not get timer for adlib emulation\n");
-        Adlib_fini (s);
-        return;
-    }
-
-    s->voice = AUD_open (s->voice, "adlib", conf.freq, SHIFT, AUD_FMT_S16);
+    as.freq = conf.freq;
+    as.nchannels = SHIFT;
+    as.fmt = AUD_FMT_S16;
+
+    AUD_register_card (audio, "adlib", &s->card);
+
+    s->voice = AUD_open_out (
+        &s->card,
+        s->voice,
+        "adlib",
+        s,
+        adlib_callback,
+        &as,
+        0                       /* XXX: little endian? */
+        );
     if (!s->voice) {
         Adlib_fini (s);
-        return;
+        return -1;
     }
 
-    s->bytes_per_second = conf.freq << SHIFT;
-    s->samples = AUD_get_buffer_size (s->voice) >> SHIFT;
+    s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
     s->mixbuf = qemu_mallocz (s->samples << SHIFT);
 
     if (!s->mixbuf) {
-        dolog ("not enough memory for adlib mixing buffer (%d)\n",
-               s->samples << SHIFT);
+        dolog ("Could not allocate mixing buffer, %d samples (each %d bytes)\n",
+               s->samples, 1 << SHIFT);
         Adlib_fini (s);
-        return;
+        return -1;
     }
+
     register_ioport_read (0x388, 4, 1, adlib_read, s);
     register_ioport_write (0x388, 4, 1, adlib_write, s);
 
@@ -309,5 +337,5 @@ void Adlib_init (void)
     register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
     register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
 
-    qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
+    return 0;
 }
index a66e032..65f96a5 100644 (file)
@@ -60,6 +60,9 @@
 
 #define APIC_SV_ENABLE (1 << 8)
 
+#define MAX_APICS 255
+#define MAX_APIC_WORDS 8
+
 typedef struct APICState {
     CPUState *cpu_env;
     uint32_t apicbase;
@@ -81,8 +84,6 @@ typedef struct APICState {
     uint32_t initial_count;
     int64_t initial_count_load_time, next_time;
     QEMUTimer *timer;
-
-    struct APICState *next_apic;
 } APICState;
 
 struct IOAPICState {
@@ -94,14 +95,95 @@ struct IOAPICState {
 };
 
 static int apic_io_memory;
-static APICState *first_local_apic = NULL;
+static APICState *local_apics[MAX_APICS + 1];
 static int last_apic_id = 0;
 
 static void apic_init_ipi(APICState *s);
 static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
 static void apic_update_irq(APICState *s);
 
-static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode,
+/* Find first bit starting from msb. Return 0 if value = 0 */
+static int fls_bit(uint32_t value)
+{
+    unsigned int ret = 0;
+
+#if defined(HOST_I386)
+    __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
+    return ret;
+#else
+    if (value > 0xffff)
+        value >>= 16, ret = 16;
+    if (value > 0xff)
+        value >>= 8, ret += 8;
+    if (value > 0xf)
+        value >>= 4, ret += 4;
+    if (value > 0x3)
+        value >>= 2, ret += 2;
+    return ret + (value >> 1);
+#endif
+}
+
+/* Find first bit starting from lsb. Return 0 if value = 0 */
+static int ffs_bit(uint32_t value)
+{
+    unsigned int ret = 0;
+
+#if defined(HOST_I386)
+    __asm__ __volatile__ ("bsf %1, %0\n" : "+r" (ret) : "rm" (value));
+    return ret;
+#else
+    if (!value)
+        return 0;
+    if (!(value & 0xffff))
+        value >>= 16, ret = 16;
+    if (!(value & 0xff))
+        value >>= 8, ret += 8;
+    if (!(value & 0xf))
+        value >>= 4, ret += 4;
+    if (!(value & 0x3))
+        value >>= 2, ret += 2;
+    if (!(value & 0x1))
+        ret++;
+    return ret;
+#endif
+}
+
+static inline void set_bit(uint32_t *tab, int index)
+{
+    int i, mask;
+    i = index >> 5;
+    mask = 1 << (index & 0x1f);
+    tab[i] |= mask;
+}
+
+static inline void reset_bit(uint32_t *tab, int index)
+{
+    int i, mask;
+    i = index >> 5;
+    mask = 1 << (index & 0x1f);
+    tab[i] &= ~mask;
+}
+
+#define foreach_apic(apic, deliver_bitmask, code) \
+{\
+    int __i, __j, __mask;\
+    for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
+        __mask = deliver_bitmask[__i];\
+        if (__mask) {\
+            for(__j = 0; __j < 32; __j++) {\
+                if (__mask & (1 << __j)) {\
+                    apic = local_apics[__i * 32 + __j];\
+                    if (apic) {\
+                        code;\
+                    }\
+                }\
+            }\
+        }\
+    }\
+}
+
+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)
 {
@@ -109,8 +191,26 @@ static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode,
 
     switch (delivery_mode) {
         case APIC_DM_LOWPRI:
+            /* XXX: search for focus processor, arbitration */
+            {
+                int i, d;
+                d = -1;
+                for(i = 0; i < MAX_APIC_WORDS; i++) {
+                    if (deliver_bitmask[i]) {
+                        d = i * 32 + ffs_bit(deliver_bitmask[i]);
+                        break;
+                    }
+                }
+                if (d >= 0) {
+                    apic_iter = local_apics[d];
+                    if (apic_iter) {
+                        apic_set_irq(apic_iter, vector_num, trigger_mode);
+                    }
+                }
+            }
+            return;
+
         case APIC_DM_FIXED:
-            /* XXX: arbitration */
             break;
 
         case APIC_DM_SMI:
@@ -119,10 +219,8 @@ static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode,
 
         case APIC_DM_INIT:
             /* normal INIT IPI sent to processors */
-            for (apic_iter = first_local_apic; apic_iter != NULL;
-                 apic_iter = apic_iter->next_apic) {
-                apic_init_ipi(apic_iter);
-            }
+            foreach_apic(apic_iter, deliver_bitmask, 
+                         apic_init_ipi(apic_iter) );
             return;
     
         case APIC_DM_EXTINT:
@@ -133,11 +231,8 @@ static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode,
             return;
     }
 
-    for (apic_iter = first_local_apic; apic_iter != NULL;
-         apic_iter = apic_iter->next_apic) {
-        if (deliver_bitmask & (1 << apic_iter->id))
-            apic_set_irq(apic_iter, vector_num, trigger_mode);
-    }
+    foreach_apic(apic_iter, deliver_bitmask, 
+                 apic_set_irq(apic_iter, vector_num, trigger_mode) );
 }
 
 void cpu_set_apic_base(CPUState *env, uint64_t val)
@@ -178,42 +273,6 @@ uint8_t cpu_get_apic_tpr(CPUX86State *env)
     return s->tpr >> 4;
 }
 
-static int fls_bit(int value)
-{
-    unsigned int ret = 0;
-
-#ifdef HOST_I386
-    __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
-    return ret;
-#else
-    if (value > 0xffff)
-        value >>= 16, ret = 16;
-    if (value > 0xff)
-        value >>= 8, ret += 8;
-    if (value > 0xf)
-        value >>= 4, ret += 4;
-    if (value > 0x3)
-        value >>= 2, ret += 2;
-    return ret + (value >> 1);
-#endif
-}
-
-static inline void set_bit(uint32_t *tab, int index)
-{
-    int i, mask;
-    i = index >> 5;
-    mask = 1 << (index & 0x1f);
-    tab[i] |= mask;
-}
-
-static inline void reset_bit(uint32_t *tab, int index)
-{
-    int i, mask;
-    i = index >> 5;
-    mask = 1 << (index & 0x1f);
-    tab[i] &= ~mask;
-}
-
 /* return -1 if no bit is set */
 static int get_highest_priority_int(uint32_t *tab)
 {
@@ -285,26 +344,37 @@ static void apic_eoi(APICState *s)
     apic_update_irq(s);
 }
 
-static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode)
+static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
+                                      uint8_t dest, uint8_t dest_mode)
 {
-    uint32_t mask = 0;
     APICState *apic_iter;
+    int i;
 
     if (dest_mode == 0) {
-        if (dest == 0xff)
-            mask = 0xff;
-        else
-            mask = 1 << dest;
+        if (dest == 0xff) {
+            memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
+        } else {
+            memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
+            set_bit(deliver_bitmask, dest);
+        }
     } else {
         /* XXX: cluster mode */
-        for (apic_iter = first_local_apic; apic_iter != NULL;
-             apic_iter = apic_iter->next_apic) {
-            if (dest & apic_iter->log_dest)
-                mask |= (1 << apic_iter->id);
+        memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
+        for(i = 0; i < MAX_APICS; i++) {
+            apic_iter = local_apics[i];
+            if (apic_iter) {
+                if (apic_iter->dest_mode == 0xf) {
+                    if (dest & apic_iter->log_dest)
+                        set_bit(deliver_bitmask, i);
+                } else if (apic_iter->dest_mode == 0x0) {
+                    if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) &&
+                        (dest & apic_iter->log_dest & 0x0f)) {
+                        set_bit(deliver_bitmask, i);
+                    }
+                }
+            }
         }
     }
-
-    return mask;
 }
 
 
@@ -317,7 +387,7 @@ static void apic_init_ipi(APICState *s)
     s->tpr = 0;
     s->spurious_vec = 0xff;
     s->log_dest = 0;
-    s->dest_mode = 0;
+    s->dest_mode = 0xf;
     memset(s->isr, 0, sizeof(s->isr));
     memset(s->tmr, 0, sizeof(s->tmr));
     memset(s->irr, 0, sizeof(s->irr));
@@ -331,61 +401,62 @@ static void apic_init_ipi(APICState *s)
     s->next_time = 0;
 }
 
+/* send a SIPI message to the CPU to start it */
+static void apic_startup(APICState *s, int vector_num)
+{
+    CPUState *env = s->cpu_env;
+    if (!(env->hflags & HF_HALTED_MASK))
+        return;
+    env->eip = 0;
+    cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12, 
+                           0xffff, 0);
+    env->hflags &= ~HF_HALTED_MASK;
+}
+
 static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
                          uint8_t delivery_mode, uint8_t vector_num,
                          uint8_t polarity, uint8_t trigger_mode)
 {
-    uint32_t deliver_bitmask = 0;
+    uint32_t deliver_bitmask[MAX_APIC_WORDS];
     int dest_shorthand = (s->icr[0] >> 18) & 3;
     APICState *apic_iter;
 
-    switch (delivery_mode) {
-        case APIC_DM_LOWPRI:
-            /* XXX: serch for focus processor, arbitration */
-            dest = s->id;
+    switch (dest_shorthand) {
+    case 0:
+        apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
+        break;
+    case 1:
+        memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
+        set_bit(deliver_bitmask, s->id);
+        break;
+    case 2:
+        memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
+        break;
+    case 3:
+        memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
+        reset_bit(deliver_bitmask, s->id);
+        break;
+    }
 
+    switch (delivery_mode) {
         case APIC_DM_INIT:
             {
                 int trig_mode = (s->icr[0] >> 15) & 1;
                 int level = (s->icr[0] >> 14) & 1;
                 if (level == 0 && trig_mode == 1) {
-                    for (apic_iter = first_local_apic; apic_iter != NULL;
-                         apic_iter = apic_iter->next_apic) {
-                        if (deliver_bitmask & (1 << apic_iter->id)) {
-                            apic_iter->arb_id = apic_iter->id;
-                        }
-                    }
+                    foreach_apic(apic_iter, deliver_bitmask, 
+                                 apic_iter->arb_id = apic_iter->id );
                     return;
                 }
             }
             break;
 
         case APIC_DM_SIPI:
-            for (apic_iter = first_local_apic; apic_iter != NULL;
-                 apic_iter = apic_iter->next_apic) {
-                if (deliver_bitmask & (1 << apic_iter->id)) {
-                    /* XXX: SMP support */
-                    /* apic_startup(apic_iter); */
-                }
-            }
+            foreach_apic(apic_iter, deliver_bitmask, 
+                         apic_startup(apic_iter, vector_num) );
             return;
     }
 
-    switch (dest_shorthand) {
-        case 0:
-            deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode);
-            break;
-        case 1:
-            deliver_bitmask = (1 << s->id);
-            break;
-        case 2:
-            deliver_bitmask = 0xffffffff;
-            break;
-        case 3:
-            deliver_bitmask = 0xffffffff & ~(1 << s->id);
-            break;
-    }
-
     apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
                      trigger_mode);
 }
@@ -534,13 +605,13 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
     case 0x28:
         val = s->esr;
         break;
-    case 0x32 ... 0x37:
-        val = s->lvt[index - 0x32];
-        break;
     case 0x30:
     case 0x31:
         val = s->icr[index & 1];
         break;
+    case 0x32 ... 0x37:
+        val = s->lvt[index - 0x32];
+        break;
     case 0x38:
         val = s->initial_count;
         break;
@@ -581,10 +652,15 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     case 0x02:
         s->id = (val >> 24);
         break;
+    case 0x03:
+        break;
     case 0x08:
         s->tpr = val;
         apic_update_irq(s);
         break;
+    case 0x09:
+    case 0x0a:
+        break;
     case 0x0b: /* EOI */
         apic_eoi(s);
         break;
@@ -598,6 +674,11 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
         s->spurious_vec = val & 0x1ff;
         apic_update_irq(s);
         break;
+    case 0x10 ... 0x17:
+    case 0x18 ... 0x1f:
+    case 0x20 ... 0x27:
+    case 0x28:
+        break;
     case 0x30:
         s->icr[0] = val;
         apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
@@ -620,6 +701,8 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
         s->initial_count_load_time = qemu_get_clock(vm_clock);
         apic_timer_update(s, s->initial_count_load_time);
         break;
+    case 0x39:
+        break;
     case 0x3e:
         {
             int v;
@@ -721,6 +804,8 @@ int apic_init(CPUState *env)
 {
     APICState *s;
 
+    if (last_apic_id >= MAX_APICS)
+        return -1;
     s = qemu_mallocz(sizeof(APICState));
     if (!s)
         return -1;
@@ -744,10 +829,8 @@ int apic_init(CPUState *env)
 
     register_savevm("apic", 0, 1, apic_save, apic_load, s);
     qemu_register_reset(apic_reset, s);
-
-    s->next_apic = first_local_apic;
-    first_local_apic = s;
     
+    local_apics[s->id] = s;
     return 0;
 }
 
@@ -762,6 +845,7 @@ static void ioapic_service(IOAPICState *s)
     uint8_t dest;
     uint8_t dest_mode;
     uint8_t polarity;
+    uint32_t deliver_bitmask[MAX_APIC_WORDS];
 
     for (i = 0; i < IOAPIC_NUM_PINS; i++) {
         mask = 1 << i;
@@ -779,8 +863,10 @@ static void ioapic_service(IOAPICState *s)
                     vector = pic_read_irq(isa_pic);
                 else
                     vector = entry & 0xff;
-                apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode),
-                                 delivery_mode, vector, polarity, trig_mode);
+                
+                apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
+                apic_bus_deliver(deliver_bitmask, delivery_mode, 
+                                 vector, polarity, trig_mode);
             }
         }
     }
index ce82869..ea13eae 100644 (file)
@@ -427,7 +427,9 @@ int DMA_write_memory (int nchan, void *buf, int pos, int len)
 /* request the emulator to transfer a new DMA memory block ASAP */
 void DMA_schedule(int nchan)
 {
-    cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
+    CPUState *env = cpu_single_env;
+    if (env)
+        cpu_interrupt(env, CPU_INTERRUPT_EXIT);
 }
 
 static void dma_reset(void *opaque)
diff --git a/qemu/hw/es1370.c b/qemu/hw/es1370.c
new file mode 100644 (file)
index 0000000..9fddd9d
--- /dev/null
@@ -0,0 +1,1062 @@
+/*
+ * QEMU ES1370 emulation
+ *
+ * Copyright (c) 2005 Vassili Karpov (malc)
+ *
+ * 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.
+ */
+
+/* #define DEBUG_ES1370 */
+/* #define VERBOSE_ES1370 */
+#define SILENT_ES1370
+
+#include "vl.h"
+
+/* Missing stuff:
+   SCTRL_P[12](END|ST)INC
+   SCTRL_P1SCTRLD
+   SCTRL_P2DACSEN
+   CTRL_DAC_SYNC
+   MIDI
+   non looped mode
+   surely more
+*/
+
+/*
+  Following macros and samplerate array were copied verbatim from
+  Linux kernel 2.4.30: drivers/sound/es1370.c
+
+  Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch)
+*/
+
+/* Start blatant GPL violation */
+
+#define ES1370_REG_CONTROL        0x00
+#define ES1370_REG_STATUS         0x04
+#define ES1370_REG_UART_DATA      0x08
+#define ES1370_REG_UART_STATUS    0x09
+#define ES1370_REG_UART_CONTROL   0x09
+#define ES1370_REG_UART_TEST      0x0a
+#define ES1370_REG_MEMPAGE        0x0c
+#define ES1370_REG_CODEC          0x10
+#define ES1370_REG_SERIAL_CONTROL 0x20
+#define ES1370_REG_DAC1_SCOUNT    0x24
+#define ES1370_REG_DAC2_SCOUNT    0x28
+#define ES1370_REG_ADC_SCOUNT     0x2c
+
+#define ES1370_REG_DAC1_FRAMEADR    0xc30
+#define ES1370_REG_DAC1_FRAMECNT    0xc34
+#define ES1370_REG_DAC2_FRAMEADR    0xc38
+#define ES1370_REG_DAC2_FRAMECNT    0xc3c
+#define ES1370_REG_ADC_FRAMEADR     0xd30
+#define ES1370_REG_ADC_FRAMECNT     0xd34
+#define ES1370_REG_PHANTOM_FRAMEADR 0xd38
+#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
+
+static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 };
+
+#define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2)
+#define DAC2_DIVTOSR(x) (1411200/((x)+2))
+
+#define CTRL_ADC_STOP   0x80000000  /* 1 = ADC stopped */
+#define CTRL_XCTL1      0x40000000  /* electret mic bias */
+#define CTRL_OPEN       0x20000000  /* no function, can be read and written */
+#define CTRL_PCLKDIV    0x1fff0000  /* ADC/DAC2 clock divider */
+#define CTRL_SH_PCLKDIV 16
+#define CTRL_MSFMTSEL   0x00008000  /* MPEG serial data fmt: 0 = Sony, 1 = I2S */
+#define CTRL_M_SBB      0x00004000  /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */
+#define CTRL_WTSRSEL    0x00003000  /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */
+#define CTRL_SH_WTSRSEL 12
+#define CTRL_DAC_SYNC   0x00000800  /* 1 = DAC2 runs off DAC1 clock */
+#define CTRL_CCB_INTRM  0x00000400  /* 1 = CCB "voice" ints enabled */
+#define CTRL_M_CB       0x00000200  /* recording source: 0 = ADC, 1 = MPEG */
+#define CTRL_XCTL0      0x00000100  /* 0 = Line in, 1 = Line out */
+#define CTRL_BREQ       0x00000080  /* 1 = test mode (internal mem test) */
+#define CTRL_DAC1_EN    0x00000040  /* enable DAC1 */
+#define CTRL_DAC2_EN    0x00000020  /* enable DAC2 */
+#define CTRL_ADC_EN     0x00000010  /* enable ADC */
+#define CTRL_UART_EN    0x00000008  /* enable MIDI uart */
+#define CTRL_JYSTK_EN   0x00000004  /* enable Joystick port (presumably at address 0x200) */
+#define CTRL_CDC_EN     0x00000002  /* enable serial (CODEC) interface */
+#define CTRL_SERR_DIS   0x00000001  /* 1 = disable PCI SERR signal */
+
+#define STAT_INTR       0x80000000  /* wired or of all interrupt bits */
+#define STAT_CSTAT      0x00000400  /* 1 = codec busy or codec write in progress */
+#define STAT_CBUSY      0x00000200  /* 1 = codec busy */
+#define STAT_CWRIP      0x00000100  /* 1 = codec write in progress */
+#define STAT_VC         0x00000060  /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */
+#define STAT_SH_VC      5
+#define STAT_MCCB       0x00000010  /* CCB int pending */
+#define STAT_UART       0x00000008  /* UART int pending */
+#define STAT_DAC1       0x00000004  /* DAC1 int pending */
+#define STAT_DAC2       0x00000002  /* DAC2 int pending */
+#define STAT_ADC        0x00000001  /* ADC int pending */
+
+#define USTAT_RXINT     0x80        /* UART rx int pending */
+#define USTAT_TXINT     0x04        /* UART tx int pending */
+#define USTAT_TXRDY     0x02        /* UART tx ready */
+#define USTAT_RXRDY     0x01        /* UART rx ready */
+
+#define UCTRL_RXINTEN   0x80        /* 1 = enable RX ints */
+#define UCTRL_TXINTEN   0x60        /* TX int enable field mask */
+#define UCTRL_ENA_TXINT 0x20        /* enable TX int */
+#define UCTRL_CNTRL     0x03        /* control field */
+#define UCTRL_CNTRL_SWR 0x03        /* software reset command */
+
+#define SCTRL_P2ENDINC    0x00380000  /*  */
+#define SCTRL_SH_P2ENDINC 19
+#define SCTRL_P2STINC     0x00070000  /*  */
+#define SCTRL_SH_P2STINC  16
+#define SCTRL_R1LOOPSEL   0x00008000  /* 0 = loop mode */
+#define SCTRL_P2LOOPSEL   0x00004000  /* 0 = loop mode */
+#define SCTRL_P1LOOPSEL   0x00002000  /* 0 = loop mode */
+#define SCTRL_P2PAUSE     0x00001000  /* 1 = pause mode */
+#define SCTRL_P1PAUSE     0x00000800  /* 1 = pause mode */
+#define SCTRL_R1INTEN     0x00000400  /* enable interrupt */
+#define SCTRL_P2INTEN     0x00000200  /* enable interrupt */
+#define SCTRL_P1INTEN     0x00000100  /* enable interrupt */
+#define SCTRL_P1SCTRLD    0x00000080  /* reload sample count register for DAC1 */
+#define SCTRL_P2DACSEN    0x00000040  /* 1 = DAC2 play back last sample when disabled */
+#define SCTRL_R1SEB       0x00000020  /* 1 = 16bit */
+#define SCTRL_R1SMB       0x00000010  /* 1 = stereo */
+#define SCTRL_R1FMT       0x00000030  /* format mask */
+#define SCTRL_SH_R1FMT    4
+#define SCTRL_P2SEB       0x00000008  /* 1 = 16bit */
+#define SCTRL_P2SMB       0x00000004  /* 1 = stereo */
+#define SCTRL_P2FMT       0x0000000c  /* format mask */
+#define SCTRL_SH_P2FMT    2
+#define SCTRL_P1SEB       0x00000002  /* 1 = 16bit */
+#define SCTRL_P1SMB       0x00000001  /* 1 = stereo */
+#define SCTRL_P1FMT       0x00000003  /* format mask */
+#define SCTRL_SH_P1FMT    0
+
+/* End blatant GPL violation */
+
+#define NB_CHANNELS 3
+#define DAC1_CHANNEL 0
+#define DAC2_CHANNEL 1
+#define ADC_CHANNEL 2
+
+#define IO_READ_PROTO(n) \
+static uint32_t n (void *opaque, uint32_t addr)
+#define IO_WRITE_PROTO(n) \
+static void n (void *opaque, uint32_t addr, uint32_t val)
+
+static void es1370_dac1_callback (void *opaque, int free);
+static void es1370_dac2_callback (void *opaque, int free);
+static void es1370_adc_callback (void *opaque, int avail);
+
+#ifdef DEBUG_ES1370
+
+#define ldebug(...) AUD_log ("es1370", __VA_ARGS__)
+
+static void print_ctl (uint32_t val)
+{
+    char buf[1024];
+
+    buf[0] = '\0';
+#define a(n) if (val & CTRL_##n) strcat (buf, " "#n)
+    a (ADC_STOP);
+    a (XCTL1);
+    a (OPEN);
+    a (MSFMTSEL);
+    a (M_SBB);
+    a (DAC_SYNC);
+    a (CCB_INTRM);
+    a (M_CB);
+    a (XCTL0);
+    a (BREQ);
+    a (DAC1_EN);
+    a (DAC2_EN);
+    a (ADC_EN);
+    a (UART_EN);
+    a (JYSTK_EN);
+    a (CDC_EN);
+    a (SERR_DIS);
+#undef a
+    AUD_log ("es1370", "ctl - PCLKDIV %d(DAC2 freq %d), freq %d,%s\n",
+             (val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV,
+             DAC2_DIVTOSR ((val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
+             dac1_samplerate[(val & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL],
+             buf);
+}
+
+static void print_sctl (uint32_t val)
+{
+    static const char *fmt_names[] = {"8M", "8S", "16M", "16S"};
+    char buf[1024];
+
+    buf[0] = '\0';
+
+#define a(n) if (val & SCTRL_##n) strcat (buf, " "#n)
+#define b(n) if (!(val & SCTRL_##n)) strcat (buf, " "#n)
+    b (R1LOOPSEL);
+    b (P2LOOPSEL);
+    b (P1LOOPSEL);
+    a (P2PAUSE);
+    a (P1PAUSE);
+    a (R1INTEN);
+    a (P2INTEN);
+    a (P1INTEN);
+    a (P1SCTRLD);
+    a (P2DACSEN);
+    if (buf[0]) {
+        strcat (buf, "\n        ");
+    }
+    else {
+        buf[0] = ' ';
+        buf[1] = '\0';
+    }
+#undef b
+#undef a
+    AUD_log ("es1370",
+             "%s"
+             "p2_end_inc %d, p2_st_inc %d, r1_fmt %s, p2_fmt %s, p1_fmt %s\n",
+             buf,
+             (val & SCTRL_P2ENDINC) >> SCTRL_SH_P2ENDINC,
+             (val & SCTRL_P2STINC) >> SCTRL_SH_P2STINC,
+             fmt_names [(val >> SCTRL_SH_R1FMT) & 3],
+             fmt_names [(val >> SCTRL_SH_P2FMT) & 3],
+             fmt_names [(val >> SCTRL_SH_P1FMT) & 3]
+        );
+}
+#else
+#define ldebug(...)
+#define print_ctl(...)
+#define print_sctl(...)
+#endif
+
+#ifdef VERBOSE_ES1370
+#define dolog(...) AUD_log ("es1370", __VA_ARGS__)
+#else
+#define dolog(...)
+#endif
+
+#ifndef SILENT_ES1370
+#define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__)
+#else
+#define lwarn(...)
+#endif
+
+struct chan {
+    uint32_t shift;
+    uint32_t leftover;
+    uint32_t scount;
+    uint32_t frame_addr;
+    uint32_t frame_cnt;
+};
+
+typedef struct ES1370State {
+    PCIDevice *pci_dev;
+
+    QEMUSoundCard card;
+    struct chan chan[NB_CHANNELS];
+    SWVoiceOut *dac_voice[2];
+    SWVoiceIn *adc_voice;
+
+    uint32_t ctl;
+    uint32_t status;
+    uint32_t mempage;
+    uint32_t codec;
+    uint32_t sctl;
+} ES1370State;
+
+typedef struct PCIES1370State {
+    PCIDevice dev;
+    ES1370State es1370;
+} PCIES1370State;
+
+struct chan_bits {
+    uint32_t ctl_en;
+    uint32_t stat_int;
+    uint32_t sctl_pause;
+    uint32_t sctl_inten;
+    uint32_t sctl_fmt;
+    uint32_t sctl_sh_fmt;
+    uint32_t sctl_loopsel;
+    void (*calc_freq) (ES1370State *s, uint32_t ctl,
+                       uint32_t *old_freq, uint32_t *new_freq);
+};
+
+static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl,
+                                   uint32_t *old_freq, uint32_t *new_freq);
+static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl,
+                                           uint32_t *old_freq,
+                                           uint32_t *new_freq);
+
+static const struct chan_bits es1370_chan_bits[] = {
+    {CTRL_DAC1_EN, STAT_DAC1, SCTRL_P1PAUSE, SCTRL_P1INTEN,
+     SCTRL_P1FMT, SCTRL_SH_P1FMT, SCTRL_P1LOOPSEL,
+     es1370_dac1_calc_freq},
+
+    {CTRL_DAC2_EN, STAT_DAC2, SCTRL_P2PAUSE, SCTRL_P2INTEN,
+     SCTRL_P2FMT, SCTRL_SH_P2FMT, SCTRL_P2LOOPSEL,
+     es1370_dac2_and_adc_calc_freq},
+
+    {CTRL_ADC_EN, STAT_ADC, 0, SCTRL_R1INTEN,
+     SCTRL_R1FMT, SCTRL_SH_R1FMT, SCTRL_R1LOOPSEL,
+     es1370_dac2_and_adc_calc_freq}
+};
+
+static void es1370_update_status (ES1370State *s, uint32_t new_status)
+{
+    uint32_t level = new_status & (STAT_DAC1 | STAT_DAC2 | STAT_ADC);
+
+    if (level) {
+        s->status = new_status | STAT_INTR;
+    }
+    else {
+        s->status = new_status & ~STAT_INTR;
+    }
+    pci_set_irq (s->pci_dev, 0, !!level);
+}
+
+static void es1370_reset (ES1370State *s)
+{
+    size_t i;
+
+    s->ctl = 1;
+    s->status = 0x60;
+    s->mempage = 0;
+    s->codec = 0;
+    s->sctl = 0;
+
+    for (i = 0; i < NB_CHANNELS; ++i) {
+        struct chan *d = &s->chan[i];
+        d->scount = 0;
+        d->leftover = 0;
+        if (i == ADC_CHANNEL) {
+            AUD_close_in (&s->card, s->adc_voice);
+            s->adc_voice = NULL;
+        }
+        else {
+            AUD_close_out (&s->card, s->dac_voice[i]);
+            s->dac_voice[i] = NULL;
+        }
+    }
+    pci_set_irq (s->pci_dev, 0, 0);
+}
+
+static void es1370_maybe_lower_irq (ES1370State *s, uint32_t sctl)
+{
+    uint32_t new_status = s->status;
+
+    if (!(sctl & SCTRL_P1INTEN) && (s->sctl & SCTRL_P1INTEN)) {
+        new_status &= ~STAT_DAC1;
+    }
+
+    if (!(sctl & SCTRL_P2INTEN) && (s->sctl & SCTRL_P2INTEN)) {
+        new_status &= ~STAT_DAC2;
+    }
+
+    if (!(sctl & SCTRL_R1INTEN) && (s->sctl & SCTRL_R1INTEN)) {
+        new_status &= ~STAT_ADC;
+    }
+
+    if (new_status != s->status) {
+        es1370_update_status (s, new_status);
+    }
+}
+
+static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl,
+                                   uint32_t *old_freq, uint32_t *new_freq)
+
+{
+    *old_freq = dac1_samplerate[(s->ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
+    *new_freq = dac1_samplerate[(ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
+}
+
+static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl,
+                                           uint32_t *old_freq,
+                                           uint32_t *new_freq)
+
+{
+    uint32_t old_pclkdiv, new_pclkdiv;
+
+    new_pclkdiv = (ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV;
+    old_pclkdiv = (s->ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV;
+    *new_freq = DAC2_DIVTOSR (new_pclkdiv);
+    *old_freq = DAC2_DIVTOSR (old_pclkdiv);
+}
+
+static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
+{
+    size_t i;
+    uint32_t old_freq, new_freq, old_fmt, new_fmt;
+
+    for (i = 0; i < NB_CHANNELS; ++i) {
+        struct chan *d = &s->chan[i];
+        const struct chan_bits *b = &es1370_chan_bits[i];
+
+        new_fmt = (sctl & b->sctl_fmt) >> b->sctl_sh_fmt;
+        old_fmt = (s->sctl & b->sctl_fmt) >> b->sctl_sh_fmt;
+
+        b->calc_freq (s, ctl, &old_freq, &new_freq);
+
+        if ((old_fmt != new_fmt) || (old_freq != new_freq)) {
+            d->shift = (new_fmt & 1) + (new_fmt >> 1);
+            ldebug ("channel %d, freq = %d, nchannels %d, fmt %d, shift %d\n",
+                    i,
+                    new_freq,
+                    1 << (new_fmt & 1),
+                    (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8,
+                    d->shift);
+            if (new_freq) {
+                audsettings_t as;
+
+                as.freq = new_freq;
+                as.nchannels = 1 << (new_fmt & 1);
+                as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8;
+
+                if (i == ADC_CHANNEL) {
+                    s->adc_voice =
+                        AUD_open_in (
+                            &s->card,
+                            s->adc_voice,
+                            "es1370.adc",
+                            s,
+                            es1370_adc_callback,
+                            &as,
+                            0   /* little endian */
+                            );
+                }
+                else {
+                    s->dac_voice[i] =
+                        AUD_open_out (
+                            &s->card,
+                            s->dac_voice[i],
+                            i ? "es1370.dac2" : "es1370.dac1",
+                            s,
+                            i ? es1370_dac2_callback : es1370_dac1_callback,
+                            &as,
+                            0   /* litle endian */
+                            );
+                }
+            }
+        }
+
+        if (((ctl ^ s->ctl) & b->ctl_en)
+            || ((sctl ^ s->sctl) & b->sctl_pause)) {
+            int on = (ctl & b->ctl_en) && !(sctl & b->sctl_pause);
+
+            if (i == ADC_CHANNEL) {
+                AUD_set_active_in (s->adc_voice, on);
+            }
+            else {
+                AUD_set_active_out (s->dac_voice[i], on);
+            }
+        }
+    }
+
+    s->ctl = ctl;
+    s->sctl = sctl;
+}
+
+static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr)
+{
+    addr &= 0xff;
+    if (addr >= 0x30 && addr <= 0x3f)
+        addr |= s->mempage << 8;
+    return addr;
+}
+
+IO_WRITE_PROTO (es1370_writeb)
+{
+    ES1370State *s = opaque;
+    addr = es1370_fixup (s, addr);
+    uint32_t shift, mask;
+
+    switch (addr) {
+    case ES1370_REG_CONTROL:
+    case ES1370_REG_CONTROL + 1:
+    case ES1370_REG_CONTROL + 2:
+    case ES1370_REG_CONTROL + 3:
+        shift = (addr - ES1370_REG_CONTROL) << 3;
+        mask = 0xff << shift;
+        val = (s->ctl & ~mask) | ((val & 0xff) << shift);
+        es1370_update_voices (s, val, s->sctl);
+        print_ctl (val);
+        break;
+    case ES1370_REG_MEMPAGE:
+        s->mempage = val;
+        break;
+    case ES1370_REG_SERIAL_CONTROL:
+    case ES1370_REG_SERIAL_CONTROL + 1:
+    case ES1370_REG_SERIAL_CONTROL + 2:
+    case ES1370_REG_SERIAL_CONTROL + 3:
+        shift = (addr - ES1370_REG_SERIAL_CONTROL) << 3;
+        mask = 0xff << shift;
+        val = (s->sctl & ~mask) | ((val & 0xff) << shift);
+        es1370_maybe_lower_irq (s, val);
+        es1370_update_voices (s, s->ctl, val);
+        print_sctl (val);
+        break;
+    default:
+        lwarn ("writeb %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+IO_WRITE_PROTO (es1370_writew)
+{
+    ES1370State *s = opaque;
+    addr = es1370_fixup (s, addr);
+    uint32_t shift, mask;
+    struct chan *d = &s->chan[0];
+
+    switch (addr) {
+    case ES1370_REG_CODEC:
+        dolog ("ignored codec write address %#x, data %#x\n",
+               (val >> 8) & 0xff, val & 0xff);
+        s->codec = val;
+        break;
+
+    case ES1370_REG_CONTROL:
+    case ES1370_REG_CONTROL + 2:
+        shift = (addr != ES1370_REG_CONTROL) << 4;
+        mask = 0xffff << shift;
+        val = (s->ctl & ~mask) | ((val & 0xffff) << shift);
+        es1370_update_voices (s, val, s->sctl);
+        print_ctl (val);
+        break;
+
+    case ES1370_REG_ADC_SCOUNT:
+        d++;
+    case ES1370_REG_DAC2_SCOUNT:
+        d++;
+    case ES1370_REG_DAC1_SCOUNT:
+        d->scount = (d->scount & ~0xffff) | (val & 0xffff);
+        break;
+
+    default:
+        lwarn ("writew %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+IO_WRITE_PROTO (es1370_writel)
+{
+    ES1370State *s = opaque;
+    struct chan *d = &s->chan[0];
+
+    addr = es1370_fixup (s, addr);
+
+    switch (addr) {
+    case ES1370_REG_CONTROL:
+        es1370_update_voices (s, val, s->sctl);
+        print_ctl (val);
+        break;
+
+    case ES1370_REG_MEMPAGE:
+        s->mempage = val & 0xf;
+        break;
+
+    case ES1370_REG_SERIAL_CONTROL:
+        es1370_maybe_lower_irq (s, val);
+        es1370_update_voices (s, s->ctl, val);
+        print_sctl (val);
+        break;
+
+    case ES1370_REG_ADC_SCOUNT:
+        d++;
+    case ES1370_REG_DAC2_SCOUNT:
+        d++;
+    case ES1370_REG_DAC1_SCOUNT:
+        d->scount = (val & 0xffff) | (d->scount & ~0xffff);
+        ldebug ("chan %d CURR_SAMP_CT %d, SAMP_CT %d\n",
+                d - &s->chan[0], val >> 16, (val & 0xffff));
+        break;
+
+    case ES1370_REG_ADC_FRAMEADR:
+        d++;
+    case ES1370_REG_DAC2_FRAMEADR:
+        d++;
+    case ES1370_REG_DAC1_FRAMEADR:
+        d->frame_addr = val;
+        ldebug ("chan %d frame address %#x\n", d - &s->chan[0], val);
+        break;
+
+    case ES1370_REG_PHANTOM_FRAMECNT:
+        lwarn ("writing to phantom frame count %#x\n", val);
+        break;
+    case ES1370_REG_PHANTOM_FRAMEADR:
+        lwarn ("writing to phantom frame address %#x\n", val);
+        break;
+
+    case ES1370_REG_ADC_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC2_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC1_FRAMECNT:
+        d->frame_cnt = val;
+        d->leftover = 0;
+        ldebug ("chan %d frame count %d, buffer size %d\n",
+                d - &s->chan[0], val >> 16, val & 0xffff);
+        break;
+
+    default:
+        lwarn ("writel %#x <- %#x\n", addr, val);
+        break;
+    }
+}
+
+IO_READ_PROTO (es1370_readb)
+{
+    ES1370State *s = opaque;
+    uint32_t val;
+
+    addr = es1370_fixup (s, addr);
+
+    switch (addr) {
+    case 0x1b:                  /* Legacy */
+        lwarn ("Attempt to read from legacy register\n");
+        val = 5;
+        break;
+    case ES1370_REG_MEMPAGE:
+        val = s->mempage;
+        break;
+    case ES1370_REG_CONTROL + 0:
+    case ES1370_REG_CONTROL + 1:
+    case ES1370_REG_CONTROL + 2:
+    case ES1370_REG_CONTROL + 3:
+        val = s->ctl >> ((addr - ES1370_REG_CONTROL) << 3);
+        break;
+    case ES1370_REG_STATUS + 0:
+    case ES1370_REG_STATUS + 1:
+    case ES1370_REG_STATUS + 2:
+    case ES1370_REG_STATUS + 3:
+        val = s->status >> ((addr - ES1370_REG_STATUS) << 3);
+        break;
+    default:
+        val = ~0;
+        lwarn ("readb %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+IO_READ_PROTO (es1370_readw)
+{
+    ES1370State *s = opaque;
+    struct chan *d = &s->chan[0];
+    uint32_t val;
+
+    addr = es1370_fixup (s, addr);
+
+    switch (addr) {
+    case ES1370_REG_ADC_SCOUNT + 2:
+        d++;
+    case ES1370_REG_DAC2_SCOUNT + 2:
+        d++;
+    case ES1370_REG_DAC1_SCOUNT + 2:
+        val = d->scount >> 16;
+        break;
+
+    case ES1370_REG_ADC_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC2_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC1_FRAMECNT:
+        val = d->frame_cnt & 0xffff;
+        break;
+
+    case ES1370_REG_ADC_FRAMECNT + 2:
+        d++;
+    case ES1370_REG_DAC2_FRAMECNT + 2:
+        d++;
+    case ES1370_REG_DAC1_FRAMECNT + 2:
+        val = d->frame_cnt >> 16;
+        break;
+
+    default:
+        val = ~0;
+        lwarn ("readw %#x -> %#x\n", addr, val);
+        break;
+    }
+
+    return val;
+}
+
+IO_READ_PROTO (es1370_readl)
+{
+    ES1370State *s = opaque;
+    uint32_t val;
+    struct chan *d = &s->chan[0];
+
+    addr = es1370_fixup (s, addr);
+
+    switch (addr) {
+    case ES1370_REG_CONTROL:
+        val = s->ctl;
+        break;
+    case ES1370_REG_STATUS:
+        val = s->status;
+        break;
+    case ES1370_REG_MEMPAGE:
+        val = s->mempage;
+        break;
+    case ES1370_REG_CODEC:
+        val = s->codec;
+        break;
+    case ES1370_REG_SERIAL_CONTROL:
+        val = s->sctl;
+        break;
+
+    case ES1370_REG_ADC_SCOUNT:
+        d++;
+    case ES1370_REG_DAC2_SCOUNT:
+        d++;
+    case ES1370_REG_DAC1_SCOUNT:
+        val = d->scount;
+#ifdef DEBUG_ES1370
+        {
+            uint32_t curr_count = d->scount >> 16;
+            uint32_t count = d->scount & 0xffff;
+
+            curr_count <<= d->shift;
+            count <<= d->shift;
+            dolog ("read scount curr %d, total %d\n", curr_count, count);
+        }
+#endif
+        break;
+
+    case ES1370_REG_ADC_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC2_FRAMECNT:
+        d++;
+    case ES1370_REG_DAC1_FRAMECNT:
+        val = d->frame_cnt;
+#ifdef DEBUG_ES1370
+        {
+            uint32_t size = ((d->frame_cnt & 0xffff) + 1) << 2;
+            uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2;
+            if (curr > size)
+                dolog ("read framecnt curr %d, size %d %d\n", curr, size,
+                       curr > size);
+        }
+#endif
+        break;
+
+    case ES1370_REG_ADC_FRAMEADR:
+        d++;
+    case ES1370_REG_DAC2_FRAMEADR:
+        d++;
+    case ES1370_REG_DAC1_FRAMEADR:
+        val = d->frame_addr;
+        break;
+
+    case ES1370_REG_PHANTOM_FRAMECNT:
+        val = ~0U;
+        lwarn ("reading from phantom frame count\n");
+        break;
+    case ES1370_REG_PHANTOM_FRAMEADR:
+        val = ~0U;
+        lwarn ("reading from phantom frame address\n");
+        break;
+
+    default:
+        val = ~0U;
+        lwarn ("readl %#x -> %#x\n", addr, val);
+        break;
+    }
+    return val;
+}
+
+
+static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
+                                   int max, int *irq)
+{
+    uint8_t tmpbuf[4096];
+    uint32_t addr = d->frame_addr;
+    int sc = d->scount & 0xffff;
+    int csc = d->scount >> 16;
+    int csc_bytes = (csc + 1) << d->shift;
+    int cnt = d->frame_cnt >> 16;
+    int size = d->frame_cnt & 0xffff;
+    int left = ((size - cnt + 1) << 2) + d->leftover;
+    int transfered = 0;
+    int temp = audio_MIN (max, audio_MIN (left, csc_bytes));
+    int index = d - &s->chan[0];
+
+    addr += (cnt << 2) + d->leftover;
+
+    if (index == ADC_CHANNEL) {
+        while (temp) {
+            int acquired, to_copy;
+
+            to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
+            acquired = AUD_read (s->adc_voice, tmpbuf, to_copy);
+            if (!acquired)
+                break;
+
+            cpu_physical_memory_write (addr, tmpbuf, acquired);
+
+            temp -= acquired;
+            addr += acquired;
+            transfered += acquired;
+        }
+    }
+    else {
+        SWVoiceOut *voice = s->dac_voice[index];
+
+        while (temp) {
+            int copied, to_copy;
+
+            to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
+            cpu_physical_memory_read (addr, tmpbuf, to_copy);
+            copied = AUD_write (voice, tmpbuf, to_copy);
+            if (!copied)
+                break;
+            temp -= copied;
+            addr += copied;
+            transfered += copied;
+        }
+    }
+
+    if (csc_bytes == transfered) {
+        *irq = 1;
+        d->scount = sc | (sc << 16);
+        ldebug ("sc = %d, rate = %f\n",
+                (sc + 1) << d->shift,
+                (sc + 1) / (double) 44100);
+    }
+    else {
+        *irq = 0;
+        d->scount = sc | (((csc_bytes - transfered - 1) >> d->shift) << 16);
+    }
+
+    cnt += (transfered + d->leftover) >> 2;
+
+    if (s->sctl & loop_sel) {
+        /* Bah, how stupid is that having a 0 represent true value?
+           i just spent few hours on this shit */
+        AUD_log ("es1370: warning", "non looping mode\n");
+    }
+    else {
+        d->frame_cnt = size;
+
+        if ((uint32_t) cnt <= d->frame_cnt)
+            d->frame_cnt |= cnt << 16;
+    }
+
+    d->leftover = (transfered + d->leftover) & 3;
+}
+
+static void es1370_run_channel (ES1370State *s, size_t chan, int free_or_avail)
+{
+    uint32_t new_status = s->status;
+    int max_bytes, irq;
+    struct chan *d = &s->chan[chan];
+    const struct chan_bits *b = &es1370_chan_bits[chan];
+
+    if (!(s->ctl & b->ctl_en) || (s->sctl & b->sctl_pause)) {
+        return;
+    }
+
+    max_bytes = free_or_avail;
+    max_bytes &= ~((1 << d->shift) - 1);
+    if (!max_bytes) {
+        return;
+    }
+
+    es1370_transfer_audio (s, d, b->sctl_loopsel, max_bytes, &irq);
+
+    if (irq) {
+        if (s->sctl & b->sctl_inten) {
+            new_status |= b->stat_int;
+        }
+    }
+
+    if (new_status != s->status) {
+        es1370_update_status (s, new_status);
+    }
+}
+
+static void es1370_dac1_callback (void *opaque, int free)
+{
+    ES1370State *s = opaque;
+
+    es1370_run_channel (s, DAC1_CHANNEL, free);
+}
+
+static void es1370_dac2_callback (void *opaque, int free)
+{
+    ES1370State *s = opaque;
+
+    es1370_run_channel (s, DAC2_CHANNEL, free);
+}
+
+static void es1370_adc_callback (void *opaque, int avail)
+{
+    ES1370State *s = opaque;
+
+    es1370_run_channel (s, ADC_CHANNEL, avail);
+}
+
+static void es1370_map (PCIDevice *pci_dev, int region_num,
+                        uint32_t addr, uint32_t size, int type)
+{
+    PCIES1370State *d = (PCIES1370State *) pci_dev;
+    ES1370State *s = &d->es1370;
+
+    (void) region_num;
+    (void) size;
+    (void) type;
+
+    register_ioport_write (addr, 0x40 * 4, 1, es1370_writeb, s);
+    register_ioport_write (addr, 0x40 * 2, 2, es1370_writew, s);
+    register_ioport_write (addr, 0x40, 4, es1370_writel, s);
+
+    register_ioport_read (addr, 0x40 * 4, 1, es1370_readb, s);
+    register_ioport_read (addr, 0x40 * 2, 2, es1370_readw, s);
+    register_ioport_read (addr, 0x40, 4, es1370_readl, s);
+}
+
+static void es1370_save (QEMUFile *f, void *opaque)
+{
+    ES1370State *s = opaque;
+    size_t i;
+
+    for (i = 0; i < NB_CHANNELS; ++i) {
+        struct chan *d = &s->chan[i];
+        qemu_put_be32s (f, &d->shift);
+        qemu_put_be32s (f, &d->leftover);
+        qemu_put_be32s (f, &d->scount);
+        qemu_put_be32s (f, &d->frame_addr);
+        qemu_put_be32s (f, &d->frame_cnt);
+    }
+    qemu_put_be32s (f, &s->ctl);
+    qemu_put_be32s (f, &s->status);
+    qemu_put_be32s (f, &s->mempage);
+    qemu_put_be32s (f, &s->codec);
+    qemu_put_be32s (f, &s->sctl);
+}
+
+static int es1370_load (QEMUFile *f, void *opaque, int version_id)
+{
+    uint32_t ctl, sctl;
+    ES1370State *s = opaque;
+    size_t i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    for (i = 0; i < NB_CHANNELS; ++i) {
+        struct chan *d = &s->chan[i];
+        qemu_get_be32s (f, &d->shift);
+        qemu_get_be32s (f, &d->leftover);
+        qemu_get_be32s (f, &d->scount);
+        qemu_get_be32s (f, &d->frame_addr);
+        qemu_get_be32s (f, &d->frame_cnt);
+        if (i == ADC_CHANNEL) {
+            if (s->adc_voice) {
+                AUD_close_in (&s->card, s->adc_voice);
+                s->adc_voice = NULL;
+            }
+        }
+        else {
+            if (s->dac_voice[i]) {
+                AUD_close_out (&s->card, s->dac_voice[i]);
+                s->dac_voice[i] = NULL;
+            }
+        }
+    }
+
+    qemu_get_be32s (f, &ctl);
+    qemu_get_be32s (f, &s->status);
+    qemu_get_be32s (f, &s->mempage);
+    qemu_get_be32s (f, &s->codec);
+    qemu_get_be32s (f, &sctl);
+
+    s->ctl = 0;
+    s->sctl = 0;
+    es1370_update_voices (s, ctl, sctl);
+    return 0;
+}
+
+static void es1370_on_reset (void *opaque)
+{
+    ES1370State *s = opaque;
+    es1370_reset (s);
+}
+
+int es1370_init (PCIBus *bus, AudioState *audio)
+{
+    PCIES1370State *d;
+    ES1370State *s;
+    uint8_t *c;
+
+    if (!bus) {
+        dolog ("No PCI bus\n");
+        return -1;
+    }
+
+    if (!audio) {
+        dolog ("No audio state\n");
+        return -1;
+    }
+
+    d = (PCIES1370State *) pci_register_device (bus, "ES1370",
+                                                sizeof (PCIES1370State),
+                                                -1, NULL, NULL);
+
+    if (!d) {
+        AUD_log (NULL, "Failed to register PCI device for ES1370\n");
+        return -1;
+    }
+
+    c = d->dev.config;
+    c[0x00] = 0x74;
+    c[0x01] = 0x12;
+    c[0x02] = 0x00;
+    c[0x03] = 0x50;
+    c[0x07] = 2 << 1;
+    c[0x0a] = 0x01;
+    c[0x0b] = 0x04;
+
+#if 1
+    c[0x2c] = 0x42;
+    c[0x2d] = 0x49;
+    c[0x2e] = 0x4c;
+    c[0x2f] = 0x4c;
+#else
+    c[0x2c] = 0x74;
+    c[0x2d] = 0x12;
+    c[0x2e] = 0x71;
+    c[0x2f] = 0x13;
+    c[0x34] = 0xdc;
+    c[0x3c] = 10;
+    c[0xdc] = 0x00;
+#endif
+
+    c[0x3d] = 1;
+    c[0x3e] = 0x0c;
+    c[0x3f] = 0x80;
+
+    s = &d->es1370;
+    s->pci_dev = &d->dev;
+
+    pci_register_io_region (&d->dev, 0, 256, PCI_ADDRESS_SPACE_IO, es1370_map);
+    register_savevm ("es1370", 0, 1, es1370_save, es1370_load, s);
+    qemu_register_reset (es1370_on_reset, s);
+
+    AUD_register_card (audio, "es1370", &s->card);
+    es1370_reset (s);
+    return 0;
+}
index e04539a..9603b74 100644 (file)
@@ -29,6 +29,8 @@
 #ifdef DEBUG_ESP
 #define DPRINTF(fmt, args...) \
 do { printf("ESP: " fmt , ##args); } while (0)
+#define pic_set_irq(irq, level) \
+do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
 #else
 #define DPRINTF(fmt, args...)
 #endif
@@ -36,6 +38,11 @@ do { printf("ESP: " fmt , ##args); } while (0)
 #define ESPDMA_REGS 4
 #define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
 #define ESP_MAXREG 0x3f
+#define TI_BUFSZ 65536
+#define DMA_VER 0xa0000000
+#define DMA_INTR 1
+#define DMA_INTREN 0x10
+#define DMA_LOADED 0x04000000
 
 typedef struct ESPState {
     BlockDriverState **bd;
@@ -44,8 +51,10 @@ typedef struct ESPState {
     int irq;
     uint32_t espdmaregs[ESPDMA_REGS];
     uint32_t ti_size;
+    uint32_t ti_rptr, ti_wptr;
     int ti_dir;
-    uint8_t ti_buf[65536];
+    uint8_t ti_buf[TI_BUFSZ];
+    int dma;
 } ESPState;
 
 #define STAT_DO 0x00
@@ -61,10 +70,153 @@ typedef struct ESPState {
 #define INTR_FC 0x08
 #define INTR_BS 0x10
 #define INTR_DC 0x20
+#define INTR_RST 0x80
 
 #define SEQ_0 0x0
 #define SEQ_CD 0x4
 
+/* XXX: stolen from ide.c, move to common ATAPI/SCSI library */
+static void lba_to_msf(uint8_t *buf, int lba)
+{
+    lba += 150;
+    buf[0] = (lba / 75) / 60;
+    buf[1] = (lba / 75) % 60;
+    buf[2] = lba % 75;
+}
+
+static inline void cpu_to_ube16(uint8_t *buf, int val)
+{
+    buf[0] = val >> 8;
+    buf[1] = val;
+}
+
+static inline void cpu_to_ube32(uint8_t *buf, unsigned int val)
+{
+    buf[0] = val >> 24;
+    buf[1] = val >> 16;
+    buf[2] = val >> 8;
+    buf[3] = val;
+}
+
+/* same toc as bochs. Return -1 if error or the toc length */
+/* XXX: check this */
+static int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track)
+{
+    uint8_t *q;
+    int len;
+    
+    if (start_track > 1 && start_track != 0xaa)
+        return -1;
+    q = buf + 2;
+    *q++ = 1; /* first session */
+    *q++ = 1; /* last session */
+    if (start_track <= 1) {
+        *q++ = 0; /* reserved */
+        *q++ = 0x14; /* ADR, control */
+        *q++ = 1;    /* track number */
+        *q++ = 0; /* reserved */
+        if (msf) {
+            *q++ = 0; /* reserved */
+            lba_to_msf(q, 0);
+            q += 3;
+        } else {
+            /* sector 0 */
+            cpu_to_ube32(q, 0);
+            q += 4;
+        }
+    }
+    /* lead out track */
+    *q++ = 0; /* reserved */
+    *q++ = 0x16; /* ADR, control */
+    *q++ = 0xaa; /* track number */
+    *q++ = 0; /* reserved */
+    if (msf) {
+        *q++ = 0; /* reserved */
+        lba_to_msf(q, nb_sectors);
+        q += 3;
+    } else {
+        cpu_to_ube32(q, nb_sectors);
+        q += 4;
+    }
+    len = q - buf;
+    cpu_to_ube16(buf, len - 2);
+    return len;
+}
+
+/* mostly same info as PearPc */
+static int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, 
+                              int session_num)
+{
+    uint8_t *q;
+    int len;
+    
+    q = buf + 2;
+    *q++ = 1; /* first session */
+    *q++ = 1; /* last session */
+
+    *q++ = 1; /* session number */
+    *q++ = 0x14; /* data track */
+    *q++ = 0; /* track number */
+    *q++ = 0xa0; /* lead-in */
+    *q++ = 0; /* min */
+    *q++ = 0; /* sec */
+    *q++ = 0; /* frame */
+    *q++ = 0;
+    *q++ = 1; /* first track */
+    *q++ = 0x00; /* disk type */
+    *q++ = 0x00;
+    
+    *q++ = 1; /* session number */
+    *q++ = 0x14; /* data track */
+    *q++ = 0; /* track number */
+    *q++ = 0xa1;
+    *q++ = 0; /* min */
+    *q++ = 0; /* sec */
+    *q++ = 0; /* frame */
+    *q++ = 0;
+    *q++ = 1; /* last track */
+    *q++ = 0x00;
+    *q++ = 0x00;
+    
+    *q++ = 1; /* session number */
+    *q++ = 0x14; /* data track */
+    *q++ = 0; /* track number */
+    *q++ = 0xa2; /* lead-out */
+    *q++ = 0; /* min */
+    *q++ = 0; /* sec */
+    *q++ = 0; /* frame */
+    if (msf) {
+        *q++ = 0; /* reserved */
+        lba_to_msf(q, nb_sectors);
+        q += 3;
+    } else {
+        cpu_to_ube32(q, nb_sectors);
+        q += 4;
+    }
+
+    *q++ = 1; /* session number */
+    *q++ = 0x14; /* ADR, control */
+    *q++ = 0;    /* track number */
+    *q++ = 1;    /* point */
+    *q++ = 0; /* min */
+    *q++ = 0; /* sec */
+    *q++ = 0; /* frame */
+    if (msf) {
+        *q++ = 0; 
+        lba_to_msf(q, 0);
+        q += 3;
+    } else {
+        *q++ = 0; 
+        *q++ = 0; 
+        *q++ = 0; 
+        *q++ = 0; 
+    }
+
+    len = q - buf;
+    cpu_to_ube16(buf, len - 2);
+    return len;
+}
+
 static void handle_satn(ESPState *s)
 {
     uint8_t buf[32];
@@ -73,23 +225,31 @@ static void handle_satn(ESPState *s)
     int64_t nb_sectors;
     int target;
 
-    dmaptr = iommu_translate(s->espdmaregs[1]);
     dmalen = s->wregs[0] | (s->wregs[1] << 8);
-    DPRINTF("Select with ATN at %8.8x len %d\n", dmaptr, dmalen);
-    DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
-    cpu_physical_memory_read(dmaptr, buf, dmalen);
+    target = s->wregs[4] & 7;
+    DPRINTF("Select with ATN len %d target %d\n", dmalen, target);
+    if (s->dma) {
+       dmaptr = iommu_translate(s->espdmaregs[1]);
+       DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr);
+       cpu_physical_memory_read(dmaptr, buf, dmalen);
+    } else {
+       buf[0] = 0;
+       memcpy(&buf[1], s->ti_buf, dmalen);
+       dmalen++;
+    }
     for (i = 0; i < dmalen; i++) {
        DPRINTF("Command %2.2x\n", buf[i]);
     }
     s->ti_dir = 0;
     s->ti_size = 0;
-    target = s->wregs[4] & 7;
+    s->ti_rptr = 0;
+    s->ti_wptr = 0;
 
-    if (target > 4 || !s->bd[target]) { // No such drive
+    if (target >= 4 || !s->bd[target]) { // No such drive
        s->rregs[4] = STAT_IN;
        s->rregs[5] = INTR_DC;
        s->rregs[6] = SEQ_0;
-       s->espdmaregs[0] |= 1;
+       s->espdmaregs[0] |= DMA_INTR;
        pic_set_irq(s->irq, 1);
        return;
     }
@@ -110,6 +270,7 @@ static void handle_satn(ESPState *s)
        memcpy(&s->ti_buf[8], "QEMU   ", 8);
        s->ti_buf[2] = 1;
        s->ti_buf[3] = 2;
+       s->ti_buf[4] = 32;
        s->ti_dir = 1;
        s->ti_size = 36;
        break;
@@ -126,7 +287,10 @@ static void handle_satn(ESPState *s)
        s->ti_buf[3] = nb_sectors & 0xff;
        s->ti_buf[4] = 0;
        s->ti_buf[5] = 0;
-       s->ti_buf[6] = 2;
+       if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM)
+           s->ti_buf[6] = 8; // sector size 2048
+       else
+           s->ti_buf[6] = 2; // sector size 512
        s->ti_buf[7] = 0;
        s->ti_dir = 1;
        s->ti_size = 8;
@@ -135,34 +299,87 @@ static void handle_satn(ESPState *s)
        {
            int64_t offset, len;
 
-           offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
-           len = (buf[8] << 8) | buf[9];
+           if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
+               offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4;
+               len = ((buf[8] << 8) | buf[9]) * 4;
+               s->ti_size = len * 2048;
+           } else {
+               offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
+               len = (buf[8] << 8) | buf[9];
+               s->ti_size = len * 512;
+           }
            DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len);
            bdrv_read(s->bd[target], offset, s->ti_buf, len);
+           // XXX error handling
            s->ti_dir = 1;
-           s->ti_size = len * 512;
            break;
        }
     case 0x2a:
        {
            int64_t offset, len;
 
-           offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
-           len = (buf[8] << 8) | buf[9];
+           if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
+               offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4;
+               len = ((buf[8] << 8) | buf[9]) * 4;
+               s->ti_size = len * 2048;
+           } else {
+               offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
+               len = (buf[8] << 8) | buf[9];
+               s->ti_size = len * 512;
+           }
            DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len);
            bdrv_write(s->bd[target], offset, s->ti_buf, len);
+           // XXX error handling
            s->ti_dir = 0;
-           s->ti_size = len * 512;
            break;
        }
+    case 0x43:
+        {
+            int start_track, format, msf, len;
+
+            msf = buf[2] & 2;
+            format = buf[3] & 0xf;
+            start_track = buf[7];
+            bdrv_get_geometry(s->bd[target], &nb_sectors);
+            DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
+            switch(format) {
+            case 0:
+                len = cdrom_read_toc(nb_sectors, buf, msf, start_track);
+                if (len < 0)
+                    goto error_cmd;
+                s->ti_size = len;
+                break;
+            case 1:
+                /* multi session : only a single session defined */
+                memset(buf, 0, 12);
+                buf[1] = 0x0a;
+                buf[2] = 0x01;
+                buf[3] = 0x01;
+                s->ti_size = 12;
+                break;
+            case 2:
+                len = cdrom_read_toc_raw(nb_sectors, buf, msf, start_track);
+                if (len < 0)
+                    goto error_cmd;
+                s->ti_size = len;
+                break;
+            default:
+            error_cmd:
+                DPRINTF("Read TOC error\n");
+                // XXX error handling
+                break;
+            }
+           s->ti_dir = 1;
+            break;
+        }
     default:
-       DPRINTF("Unknown command (%2.2x)\n", buf[1]);
+       DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]);
        break;
     }
     s->rregs[4] = STAT_IN | STAT_TC | STAT_DI;
     s->rregs[5] = INTR_BS | INTR_FC;
     s->rregs[6] = SEQ_CD;
-    s->espdmaregs[0] |= 1;
+    s->espdmaregs[0] |= DMA_INTR;
     pic_set_irq(s->irq, 1);
 }
 
@@ -170,17 +387,27 @@ static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
 {
     uint32_t dmaptr, dmalen;
 
-    dmaptr = iommu_translate(s->espdmaregs[1]);
     dmalen = s->wregs[0] | (s->wregs[1] << 8);
-    DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
-    cpu_physical_memory_write(dmaptr, buf, len);
-    s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
-    s->rregs[5] = INTR_BS | INTR_FC;
-    s->rregs[6] = SEQ_CD;
-    s->espdmaregs[0] |= 1;
+    DPRINTF("Transfer status len %d\n", dmalen);
+    if (s->dma) {
+       dmaptr = iommu_translate(s->espdmaregs[1]);
+       DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
+       cpu_physical_memory_write(dmaptr, buf, len);
+       s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
+       s->rregs[5] = INTR_BS | INTR_FC;
+       s->rregs[6] = SEQ_CD;
+    } else {
+       memcpy(s->ti_buf, buf, len);
+       s->ti_size = dmalen;
+       s->ti_rptr = 0;
+       s->ti_wptr = 0;
+       s->rregs[7] = dmalen;
+    }
+    s->espdmaregs[0] |= DMA_INTR;
     pic_set_irq(s->irq, 1);
 
 }
+
 static const uint8_t okbuf[] = {0, 0};
 
 static void handle_ti(ESPState *s)
@@ -188,21 +415,28 @@ static void handle_ti(ESPState *s)
     uint32_t dmaptr, dmalen;
     unsigned int i;
 
-    dmaptr = iommu_translate(s->espdmaregs[1]);
     dmalen = s->wregs[0] | (s->wregs[1] << 8);
-    DPRINTF("Transfer Information at %8.8x len %d\n", dmaptr, dmalen);
-    DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
-    for (i = 0; i < s->ti_size; i++) {
-       dmaptr = iommu_translate(s->espdmaregs[1] + i);
-       if (s->ti_dir)
-           cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1);
-       else
-           cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1);
-    }
-    s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
-    s->rregs[5] = INTR_BS;
-    s->rregs[6] = 0;
-    s->espdmaregs[0] |= 1;
+    DPRINTF("Transfer Information len %d\n", dmalen);
+    if (s->dma) {
+       dmaptr = iommu_translate(s->espdmaregs[1]);
+       DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr);
+       for (i = 0; i < s->ti_size; i++) {
+           dmaptr = iommu_translate(s->espdmaregs[1] + i);
+           if (s->ti_dir)
+               cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1);
+           else
+               cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1);
+       }
+       s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
+       s->rregs[5] = INTR_BS;
+       s->rregs[6] = 0;
+       s->espdmaregs[0] |= DMA_INTR;
+    } else {
+       s->ti_size = dmalen;
+       s->ti_rptr = 0;
+       s->ti_wptr = 0;
+       s->rregs[7] = dmalen;
+    }  
     pic_set_irq(s->irq, 1);
 }
 
@@ -220,11 +454,30 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
     uint32_t saddr;
 
     saddr = (addr & ESP_MAXREG) >> 2;
+    DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
     switch (saddr) {
+    case 2:
+       // FIFO
+       if (s->ti_size > 0) {
+           s->ti_size--;
+           s->rregs[saddr] = s->ti_buf[s->ti_rptr++];
+           pic_set_irq(s->irq, 1);
+       }
+       if (s->ti_size == 0) {
+            s->ti_rptr = 0;
+            s->ti_wptr = 0;
+        }
+       break;
+    case 5:
+        // interrupt
+        // Clear status bits except TC
+        s->rregs[4] &= STAT_TC;
+        pic_set_irq(s->irq, 0);
+       s->espdmaregs[0] &= ~DMA_INTR;
+        break;
     default:
        break;
     }
-    DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
     return s->rregs[saddr];
 }
 
@@ -236,16 +489,32 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
     saddr = (addr & ESP_MAXREG) >> 2;
     DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
     switch (saddr) {
+    case 0:
+    case 1:
+        s->rregs[saddr] = val;
+        break;
+    case 2:
+       // FIFO
+       s->ti_size++;
+       s->ti_buf[s->ti_wptr++] = val & 0xff;
+       break;
     case 3:
+        s->rregs[saddr] = val;
        // Command
+       if (val & 0x80) {
+           s->dma = 1;
+       } else {
+           s->dma = 0;
+       }
        switch(val & 0x7f) {
        case 0:
            DPRINTF("NOP (%2.2x)\n", val);
            break;
        case 1:
            DPRINTF("Flush FIFO (%2.2x)\n", val);
-           s->rregs[6] = 0;
+            //s->ti_size = 0;
            s->rregs[5] = INTR_FC;
+           s->rregs[6] = 0;
            break;
        case 2:
            DPRINTF("Chip reset (%2.2x)\n", val);
@@ -253,6 +522,11 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
            break;
        case 3:
            DPRINTF("Bus reset (%2.2x)\n", val);
+           s->rregs[5] = INTR_RST;
+            if (!(s->wregs[8] & 0x40)) {
+                s->espdmaregs[0] |= DMA_INTR;
+                pic_set_irq(s->irq, 1);
+            }
            break;
        case 0x10:
            handle_ti(s);
@@ -278,13 +552,23 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
            handle_satn(s);
            break;
        default:
-           DPRINTF("Unhandled command (%2.2x)\n", val);
+           DPRINTF("Unhandled ESP command (%2.2x)\n", val);
            break;
        }
        break;
     case 4 ... 7:
-    case 9 ... 0xf:
        break;
+    case 8:
+        s->rregs[saddr] = val;
+        break;
+    case 9 ... 10:
+        break;
+    case 11:
+        s->rregs[saddr] = val & 0x15;
+        break;
+    case 12 ... 15:
+        s->rregs[saddr] = val;
+        break;
     default:
        break;
     }
@@ -309,7 +593,8 @@ static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
     uint32_t saddr;
 
     saddr = (addr & ESPDMA_MAXADDR) >> 2;
-    DPRINTF("read dmareg[%d]: 0x%2.2x\n", saddr, s->espdmaregs[saddr]);
+    DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
+
     return s->espdmaregs[saddr];
 }
 
@@ -319,12 +604,23 @@ static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t va
     uint32_t saddr;
 
     saddr = (addr & ESPDMA_MAXADDR) >> 2;
-    DPRINTF("write dmareg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->espdmaregs[saddr], val);
+    DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val);
     switch (saddr) {
     case 0:
-       if (!(val & 0x10))
+       if (!(val & DMA_INTREN))
            pic_set_irq(s->irq, 0);
+       if (val & 0x80) {
+            esp_reset(s);
+        } else if (val & 0x40) {
+            val &= ~0x40;
+        } else if (val == 0)
+            val = 0x40;
+        val &= 0x0fffffff;
+        val |= DMA_VER;
        break;
+    case 1:
+        s->espdmaregs[0] = DMA_LOADED;
+        break;
     default:
        break;
     }
@@ -353,6 +649,12 @@ static void esp_save(QEMUFile *f, void *opaque)
     qemu_put_be32s(f, &s->irq);
     for (i = 0; i < ESPDMA_REGS; i++)
        qemu_put_be32s(f, &s->espdmaregs[i]);
+    qemu_put_be32s(f, &s->ti_size);
+    qemu_put_be32s(f, &s->ti_rptr);
+    qemu_put_be32s(f, &s->ti_wptr);
+    qemu_put_be32s(f, &s->ti_dir);
+    qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
+    qemu_put_be32s(f, &s->dma);
 }
 
 static int esp_load(QEMUFile *f, void *opaque, int version_id)
@@ -368,6 +670,12 @@ static int esp_load(QEMUFile *f, void *opaque, int version_id)
     qemu_get_be32s(f, &s->irq);
     for (i = 0; i < ESPDMA_REGS; i++)
        qemu_get_be32s(f, &s->espdmaregs[i]);
+    qemu_get_be32s(f, &s->ti_size);
+    qemu_get_be32s(f, &s->ti_rptr);
+    qemu_get_be32s(f, &s->ti_wptr);
+    qemu_get_be32s(f, &s->ti_dir);
+    qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
+    qemu_get_be32s(f, &s->dma);
 
     return 0;
 }
index d65da9a..4980cef 100644 (file)
@@ -45,9 +45,9 @@ static inline int check_irq(HeathrowPIC *pic)
 static void heathrow_pic_update(HeathrowPICS *s)
 {
     if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
-        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+        cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD);
     } else {
-        cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+        cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD);
     }
 }
 
diff --git a/qemu/hw/integratorcp.c b/qemu/hw/integratorcp.c
new file mode 100644 (file)
index 0000000..1979c39
--- /dev/null
@@ -0,0 +1,1233 @@
+/* 
+ * ARM Integrator CP System emulation.
+ *
+ * Copyright (c) 2005 CodeSourcery, LLC.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the GPL
+ */
+
+#include <vl.h>
+
+#define KERNEL_ARGS_ADDR 0x100
+#define KERNEL_LOAD_ADDR 0x00010000
+#define INITRD_LOAD_ADDR 0x00800000
+
+/* 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)
+{
+}
+
+void irq_info(void)
+{
+}
+
+void vga_update_display(void)
+{
+}
+
+void vga_screen_dump(const char *filename)
+{
+}
+
+void vga_invalidate_display(void)
+{
+}
+
+void DMA_run (void)
+{
+}
+
+typedef struct {
+    uint32_t flash_offset;
+    uint32_t cm_osc;
+    uint32_t cm_ctrl;
+    uint32_t cm_lock;
+    uint32_t cm_auxosc;
+    uint32_t cm_sdram;
+    uint32_t cm_init;
+    uint32_t cm_flags;
+    uint32_t cm_nvflags;
+    uint32_t int_level;
+    uint32_t irq_enabled;
+    uint32_t fiq_enabled;
+} integratorcm_state;
+
+static uint8_t integrator_spd[128] = {
+   128, 8, 4, 11, 9, 1, 64, 0,  2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
+   0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
+};
+
+static uint32_t integratorcm_read(void *opaque, target_phys_addr_t offset)
+{
+    integratorcm_state *s = (integratorcm_state *)opaque;
+    offset -= 0x10000000;
+    if (offset >= 0x100 && offset < 0x200) {
+        /* CM_SPD */
+        if (offset >= 0x180)
+            return 0;
+        return integrator_spd[offset >> 2];
+    }
+    switch (offset >> 2) {
+    case 0: /* CM_ID */
+        return 0x411a3001;
+    case 1: /* CM_PROC */
+        return 0;
+    case 2: /* CM_OSC */
+        return s->cm_osc;
+    case 3: /* CM_CTRL */
+        return s->cm_ctrl;
+    case 4: /* CM_STAT */
+        return 0x00100000;
+    case 5: /* CM_LOCK */
+        if (s->cm_lock == 0xa05f) {
+            return 0x1a05f;
+        } else {
+            return s->cm_lock;
+        }
+    case 6: /* CM_LMBUSCNT */
+        /* ??? High frequency timer.  */
+        cpu_abort(cpu_single_env, "integratorcm_read: CM_LMBUSCNT");
+    case 7: /* CM_AUXOSC */
+        return s->cm_auxosc;
+    case 8: /* CM_SDRAM */
+        return s->cm_sdram;
+    case 9: /* CM_INIT */
+        return s->cm_init;
+    case 10: /* CM_REFCT */
+        /* ??? High frequency timer.  */
+        cpu_abort(cpu_single_env, "integratorcm_read: CM_REFCT");
+    case 12: /* CM_FLAGS */
+        return s->cm_flags;
+    case 14: /* CM_NVFLAGS */
+        return s->cm_nvflags;
+    case 16: /* CM_IRQ_STAT */
+        return s->int_level & s->irq_enabled;
+    case 17: /* CM_IRQ_RSTAT */
+        return s->int_level;
+    case 18: /* CM_IRQ_ENSET */
+        return s->irq_enabled;
+    case 20: /* CM_SOFT_INTSET */
+        return s->int_level & 1;
+    case 24: /* CM_FIQ_STAT */
+        return s->int_level & s->fiq_enabled;
+    case 25: /* CM_FIQ_RSTAT */
+        return s->int_level;
+    case 26: /* CM_FIQ_ENSET */
+        return s->fiq_enabled;
+    case 32: /* CM_VOLTAGE_CTL0 */
+    case 33: /* CM_VOLTAGE_CTL1 */
+    case 34: /* CM_VOLTAGE_CTL2 */
+    case 35: /* CM_VOLTAGE_CTL3 */
+        /* ??? Voltage control unimplemented.  */
+        return 0;
+    default:
+        cpu_abort (cpu_single_env,
+            "integratorcm_read: Unimplemented offset 0x%x\n", offset);
+        return 0;
+    }
+}
+
+static void integratorcm_do_remap(integratorcm_state *s, int flash)
+{
+    if (flash) {
+        cpu_register_physical_memory(0, 0x100000, IO_MEM_RAM);
+    } else {
+        cpu_register_physical_memory(0, 0x100000, s->flash_offset | IO_MEM_RAM);
+    }
+    //??? tlb_flush (cpu_single_env, 1);
+}
+
+static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value)
+{
+    if (value & 8) {
+        cpu_abort(cpu_single_env, "Board reset\n");
+    }
+    if ((s->cm_init ^ value) & 4) {
+        integratorcm_do_remap(s, (value & 4) == 0);
+    }
+    if ((s->cm_init ^ value) & 1) {
+        printf("Green LED %s\n", (value & 1) ? "on" : "off");
+    }
+    s->cm_init = (s->cm_init & ~ 5) | (value ^ 5);
+}
+
+static void integratorcm_update(integratorcm_state *s)
+{
+    /* ??? The CPU irq/fiq is raised when either the core module or base PIC
+       are active.  */
+    if (s->int_level & (s->irq_enabled | s->fiq_enabled))
+        cpu_abort(cpu_single_env, "Core module interrupt\n");
+}
+
+static void integratorcm_write(void *opaque, target_phys_addr_t offset,
+                               uint32_t value)
+{
+    integratorcm_state *s = (integratorcm_state *)opaque;
+    offset -= 0x10000000;
+    switch (offset >> 2) {
+    case 2: /* CM_OSC */
+        if (s->cm_lock == 0xa05f)
+            s->cm_osc = value;
+        break;
+    case 3: /* CM_CTRL */
+        integratorcm_set_ctrl(s, value);
+        break;
+    case 5: /* CM_LOCK */
+        s->cm_lock = value & 0xffff;
+        break;
+    case 7: /* CM_AUXOSC */
+        if (s->cm_lock == 0xa05f)
+            s->cm_auxosc = value;
+        break;
+    case 8: /* CM_SDRAM */
+        s->cm_sdram = value;
+        break;
+    case 9: /* CM_INIT */
+        /* ??? This can change the memory bus frequency.  */
+        s->cm_init = value;
+        break;
+    case 12: /* CM_FLAGSS */
+        s->cm_flags |= value;
+        break;
+    case 13: /* CM_FLAGSC */
+        s->cm_flags &= ~value;
+        break;
+    case 14: /* CM_NVFLAGSS */
+        s->cm_nvflags |= value;
+        break;
+    case 15: /* CM_NVFLAGSS */
+        s->cm_nvflags &= ~value;
+        break;
+    case 18: /* CM_IRQ_ENSET */
+        s->irq_enabled |= value;
+        integratorcm_update(s);
+        break;
+    case 19: /* CM_IRQ_ENCLR */
+        s->irq_enabled &= ~value;
+        integratorcm_update(s);
+        break;
+    case 20: /* CM_SOFT_INTSET */
+        s->int_level |= (value & 1);
+        integratorcm_update(s);
+        break;
+    case 21: /* CM_SOFT_INTCLR */
+        s->int_level &= ~(value & 1);
+        integratorcm_update(s);
+        break;
+    case 26: /* CM_FIQ_ENSET */
+        s->fiq_enabled |= value;
+        integratorcm_update(s);
+        break;
+    case 27: /* CM_FIQ_ENCLR */
+        s->fiq_enabled &= ~value;
+        integratorcm_update(s);
+        break;
+    case 32: /* CM_VOLTAGE_CTL0 */
+    case 33: /* CM_VOLTAGE_CTL1 */
+    case 34: /* CM_VOLTAGE_CTL2 */
+    case 35: /* CM_VOLTAGE_CTL3 */
+        /* ??? Voltage control unimplemented.  */
+        break;
+    default:
+        cpu_abort (cpu_single_env,
+            "integratorcm_write: Unimplemented offset 0x%x\n", offset);
+        break;
+    }
+}
+
+/* Integrator/CM control registers.  */
+
+static CPUReadMemoryFunc *integratorcm_readfn[] = {
+   integratorcm_read,
+   integratorcm_read,
+   integratorcm_read
+};
+
+static CPUWriteMemoryFunc *integratorcm_writefn[] = {
+   integratorcm_write,
+   integratorcm_write,
+   integratorcm_write
+};
+
+static void integratorcm_init(int memsz, uint32_t flash_offset)
+{
+    int iomemtype;
+    integratorcm_state *s;
+
+    s = (integratorcm_state *)qemu_mallocz(sizeof(integratorcm_state));
+    s->cm_osc = 0x01000048;
+    /* ??? What should the high bits of this value be?  */
+    s->cm_auxosc = 0x0007feff;
+    s->cm_sdram = 0x00011122;
+    if (memsz >= 256) {
+        integrator_spd[31] = 64;
+        s->cm_sdram |= 0x10;
+    } else if (memsz >= 128) {
+        integrator_spd[31] = 32;
+        s->cm_sdram |= 0x0c;
+    } else if (memsz >= 64) {
+        integrator_spd[31] = 16;
+        s->cm_sdram |= 0x08;
+    } else if (memsz >= 32) {
+        integrator_spd[31] = 4;
+        s->cm_sdram |= 0x04;
+    } else {
+        integrator_spd[31] = 2;
+    }
+    memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
+    s->cm_init = 0x00000112;
+    s->flash_offset = flash_offset;
+
+    iomemtype = cpu_register_io_memory(0, integratorcm_readfn,
+                                       integratorcm_writefn, s);
+    cpu_register_physical_memory(0x10000000, 0x007fffff, iomemtype);
+    integratorcm_do_remap(s, 1);
+    /* ??? Save/restore.  */
+}
+
+/* Integrator/CP hardware emulation.  */
+/* Primary interrupt controller.  */
+
+typedef struct icp_pic_state
+{
+  uint32_t base;
+  uint32_t level;
+  uint32_t irq_enabled;
+  uint32_t fiq_enabled;
+  void *parent;
+  /* -1 if parent is a cpu, otherwise IRQ number on parent PIC.  */
+  int parent_irq;
+} icp_pic_state;
+
+static void icp_pic_update(icp_pic_state *s)
+{
+    CPUState *env;
+    if (s->parent_irq != -1) {
+        uint32_t flags;
+
+        flags = (s->level & s->irq_enabled);
+        pic_set_irq_new(s->parent, s->parent_irq,
+                        flags != 0);
+        return;
+    }
+    /* Raise CPU interrupt.  */
+    env = (CPUState *)s->parent;
+    if (s->level & s->fiq_enabled) {
+        cpu_interrupt (env, CPU_INTERRUPT_FIQ);
+    } else {
+        cpu_reset_interrupt (env, CPU_INTERRUPT_FIQ);
+    }
+    if (s->level & s->irq_enabled) {
+      cpu_interrupt (env, CPU_INTERRUPT_HARD);
+    } else {
+      cpu_reset_interrupt (env, CPU_INTERRUPT_HARD);
+    }
+}
+
+void pic_set_irq_new(void *opaque, int irq, int level)
+{
+    icp_pic_state *s = (icp_pic_state *)opaque;
+    if (level)
+        s->level |= 1 << irq;
+    else
+        s->level &= ~(1 << irq);
+    icp_pic_update(s);
+}
+
+static uint32_t icp_pic_read(void *opaque, target_phys_addr_t offset)
+{
+    icp_pic_state *s = (icp_pic_state *)opaque;
+
+    offset -= s->base;
+    switch (offset >> 2) {
+    case 0: /* IRQ_STATUS */
+        return s->level & s->irq_enabled;
+    case 1: /* IRQ_RAWSTAT */
+        return s->level;
+    case 2: /* IRQ_ENABLESET */
+        return s->irq_enabled;
+    case 4: /* INT_SOFTSET */
+        return s->level & 1;
+    case 8: /* FRQ_STATUS */
+        return s->level & s->fiq_enabled;
+    case 9: /* FRQ_RAWSTAT */
+        return s->level;
+    case 10: /* FRQ_ENABLESET */
+        return s->fiq_enabled;
+    case 3: /* IRQ_ENABLECLR */
+    case 5: /* INT_SOFTCLR */
+    case 11: /* FRQ_ENABLECLR */
+    default:
+        printf ("icp_pic_read: Bad register offset 0x%x\n", offset);
+        return 0;
+    }
+}
+
+static void icp_pic_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    icp_pic_state *s = (icp_pic_state *)opaque;
+    offset -= s->base;
+
+    switch (offset >> 2) {
+    case 2: /* IRQ_ENABLESET */
+        s->irq_enabled |= value;
+        break;
+    case 3: /* IRQ_ENABLECLR */
+        s->irq_enabled &= ~value;
+        break;
+    case 4: /* INT_SOFTSET */
+        if (value & 1)
+            pic_set_irq_new(s, 0, 1);
+        break;
+    case 5: /* INT_SOFTCLR */
+        if (value & 1)
+            pic_set_irq_new(s, 0, 0);
+        break;
+    case 10: /* FRQ_ENABLESET */
+        s->fiq_enabled |= value;
+        break;
+    case 11: /* FRQ_ENABLECLR */
+        s->fiq_enabled &= ~value;
+        break;
+    case 0: /* IRQ_STATUS */
+    case 1: /* IRQ_RAWSTAT */
+    case 8: /* FRQ_STATUS */
+    case 9: /* FRQ_RAWSTAT */
+    default:
+        printf ("icp_pic_write: Bad register offset 0x%x\n", offset);
+        return;
+    }
+    icp_pic_update(s);
+}
+
+static CPUReadMemoryFunc *icp_pic_readfn[] = {
+   icp_pic_read,
+   icp_pic_read,
+   icp_pic_read
+};
+
+static CPUWriteMemoryFunc *icp_pic_writefn[] = {
+   icp_pic_write,
+   icp_pic_write,
+   icp_pic_write
+};
+
+static icp_pic_state *icp_pic_init(uint32_t base, void *parent,
+                                   int parent_irq)
+{
+    icp_pic_state *s;
+    int iomemtype;
+
+    s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state));
+    if (!s)
+        return NULL;
+
+    s->base = base;
+    s->parent = parent;
+    s->parent_irq = parent_irq;
+    iomemtype = cpu_register_io_memory(0, icp_pic_readfn,
+                                       icp_pic_writefn, s);
+    cpu_register_physical_memory(base, 0x007fffff, iomemtype);
+    /* ??? Save/restore.  */
+    return s;
+}
+
+/* Timers.  */
+
+/* System bus clock speed (40MHz) for timer 0.  Not sure about this value.  */
+#define ICP_BUS_FREQ 40000000
+
+typedef struct {
+    int64_t next_time;
+    int64_t expires[3];
+    int64_t loaded[3];
+    QEMUTimer *timer;
+    icp_pic_state *pic;
+    uint32_t base;
+    uint32_t control[3];
+    uint32_t count[3];
+    uint32_t limit[3];
+    int freq[3];
+    int int_level[3];
+} icp_pit_state;
+
+/* Calculate the new expiry time of the given timer.  */
+
+static void icp_pit_reload(icp_pit_state *s, int n)
+{
+    int64_t delay;
+
+    s->loaded[n] = s->expires[n];
+    delay = muldiv64(s->count[n], ticks_per_sec, s->freq[n]);
+    if (delay == 0)
+        delay = 1;
+    s->expires[n] += delay;
+}
+
+/* Check all active timers, and schedule the next timer interrupt.  */
+
+static void icp_pit_update(icp_pit_state *s, int64_t now)
+{
+    int n;
+    int64_t next;
+
+    next = now;
+    for (n = 0; n < 3; n++) {
+        /* Ignore disabled timers.  */
+        if ((s->control[n] & 0x80) == 0)
+            continue;
+        /* Ignore expired one-shot timers.  */
+        if (s->count[n] == 0 && s->control[n] & 1)
+            continue;
+        if (s->expires[n] - now <= 0) {
+            /* Timer has expired.  */
+            s->int_level[n] = 1;
+            if (s->control[n] & 1) {
+                /* One-shot.  */
+                s->count[n] = 0;
+            } else {
+                if ((s->control[n] & 0x40) == 0) {
+                    /* Free running.  */
+                    if (s->control[n] & 2)
+                        s->count[n] = 0xffffffff;
+                    else
+                        s->count[n] = 0xffff;
+                } else {
+                      /* Periodic.  */
+                      s->count[n] = s->limit[n];
+                }
+            }
+        }
+        while (s->expires[n] - now <= 0) {
+            icp_pit_reload(s, n);
+        }
+    }
+    /* Update interrupts.  */
+    for (n = 0; n < 3; n++) {
+        if (s->int_level[n] && (s->control[n] & 0x20)) {
+            pic_set_irq_new(s->pic, 5 + n, 1);
+        } else {
+            pic_set_irq_new(s->pic, 5 + n, 0);
+        }
+        if (next - s->expires[n] < 0)
+            next = s->expires[n];
+    }
+    /* 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 icp_pit_getcount(icp_pit_state *s, int n, int64_t now)
+{
+    int64_t elapsed;
+    int64_t period;
+
+    if (s->count[n] == 0)
+        return 0;
+    if ((s->control[n] & 0x80) == 0)
+        return s->count[n];
+    elapsed = now - s->loaded[n];
+    period = s->expires[n] - s->loaded[n];
+    /* 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 (elapsed > period)
+        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;
+        elapsed >>= 1;
+    }
+    return ((uint64_t)s->count[n] * (uint64_t)(int32_t)elapsed)
+            / (int32_t)period;
+}
+
+static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
+{
+    int n;
+    icp_pit_state *s = (icp_pit_state *)opaque;
+
+    offset -= s->base;
+    n = offset >> 8;
+    if (n > 2)
+        cpu_abort (cpu_single_env, "icp_pit_read: Bad timer %x\n", offset);
+    switch ((offset & 0xff) >> 2) {
+    case 0: /* TimerLoad */
+    case 6: /* TimerBGLoad */
+        return s->limit[n];
+    case 1: /* TimerValue */
+        return icp_pit_getcount(s, n, qemu_get_clock(vm_clock));
+    case 2: /* TimerControl */
+        return s->control[n];
+    case 4: /* TimerRIS */
+        return s->int_level[n];
+    case 5: /* TimerMIS */
+        if ((s->control[n] & 0x20) == 0)
+            return 0;
+        return s->int_level[n];
+    default:
+        cpu_abort (cpu_single_env, "icp_pit_read: Bad offset %x\n", offset);
+        return 0;
+    }
+}
+
+static void icp_pit_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    icp_pit_state *s = (icp_pit_state *)opaque;
+    int n;
+    int64_t now;
+
+    now = qemu_get_clock(vm_clock);
+    offset -= s->base;
+    n = offset >> 8;
+    if (n > 2)
+        cpu_abort (cpu_single_env, "icp_pit_write: Bad offset %x\n", offset);
+
+    switch ((offset & 0xff) >> 2) {
+    case 0: /* TimerLoad */
+        s->limit[n] = value;
+        s->count[n] = value;
+        s->expires[n] = now;
+        icp_pit_reload(s, n);
+        break;
+    case 1: /* TimerValue */
+        /* ??? Linux seems to want to write to this readonly register.
+           Ignore it.  */
+        break;
+    case 2: /* TimerControl */
+        if (s->control[n] & 0x80) {
+            /* 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[n] = icp_pit_getcount(s, n, now);
+        }
+        s->control[n] = value;
+        if (n == 0)
+            s->freq[n] = ICP_BUS_FREQ;
+        else
+            s->freq[n] = 1000000;
+        /* ??? Need to recalculate expiry time after changing divisor.  */
+        switch ((value >> 2) & 3) {
+        case 1: s->freq[n] >>= 4; break;
+        case 2: s->freq[n] >>= 8; break;
+        }
+        if (s->control[n] & 0x80) {
+            /* Restart the timer if still enabled.  */
+            s->expires[n] = now;
+            icp_pit_reload(s, n);
+        }
+        break;
+    case 3: /* TimerIntClr */
+        s->int_level[n] = 0;
+        break;
+    case 6: /* TimerBGLoad */
+        s->limit[n] = value;
+        break;
+    default:
+        cpu_abort (cpu_single_env, "icp_pit_write: Bad offset %x\n", offset);
+    }
+    icp_pit_update(s, now);
+}
+
+static void icp_pit_tick(void *opaque)
+{
+    int64_t now;
+
+    now = qemu_get_clock(vm_clock);
+    icp_pit_update((icp_pit_state *)opaque, now);
+}
+
+static CPUReadMemoryFunc *icp_pit_readfn[] = {
+   icp_pit_read,
+   icp_pit_read,
+   icp_pit_read
+};
+
+static CPUWriteMemoryFunc *icp_pit_writefn[] = {
+   icp_pit_write,
+   icp_pit_write,
+   icp_pit_write
+};
+
+static void icp_pit_init(uint32_t base, icp_pic_state *pic)
+{
+    int iomemtype;
+    icp_pit_state *s;
+    int n;
+
+    s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));
+    s->base = base;
+    s->pic = pic;
+    s->freq[0] = ICP_BUS_FREQ;
+    s->freq[1] = 1000000;
+    s->freq[2] = 1000000;
+    for (n = 0; n < 3; n++) {
+        s->control[n] = 0x20;
+        s->count[n] = 0xffffffff;
+    }
+
+    iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
+                                       icp_pit_writefn, s);
+    cpu_register_physical_memory(base, 0x007fffff, iomemtype);
+    s->timer = qemu_new_timer(vm_clock, icp_pit_tick, s);
+    /* ??? Save/restore.  */
+}
+
+/* ARM PrimeCell PL011 UART */
+
+typedef struct {
+    uint32_t base;
+    uint32_t readbuff;
+    uint32_t flags;
+    uint32_t lcr;
+    uint32_t cr;
+    uint32_t dmacr;
+    uint32_t int_enabled;
+    uint32_t int_level;
+    uint32_t read_fifo[16];
+    uint32_t ilpr;
+    uint32_t ibrd;
+    uint32_t fbrd;
+    uint32_t ifl;
+    int read_pos;
+    int read_count;
+    int read_trigger;
+    CharDriverState *chr;
+    icp_pic_state *pic;
+    int irq;
+} pl011_state;
+
+#define PL011_INT_TX 0x20
+#define PL011_INT_RX 0x10
+
+#define PL011_FLAG_TXFE 0x80
+#define PL011_FLAG_RXFF 0x40
+#define PL011_FLAG_TXFF 0x20
+#define PL011_FLAG_RXFE 0x10
+
+static const unsigned char pl011_id[] =
+{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+
+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);
+}
+
+static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
+{
+    pl011_state *s = (pl011_state *)opaque;
+    uint32_t c;
+
+    offset -= s->base;
+    if (offset >= 0xfe0 && offset < 0x1000) {
+        return pl011_id[(offset - 0xfe0) >> 2];
+    }
+    switch (offset >> 2) {
+    case 0: /* UARTDR */
+        s->flags &= ~PL011_FLAG_RXFF;
+        c = s->read_fifo[s->read_pos];
+        if (s->read_count > 0) {
+            s->read_count--;
+            if (++s->read_pos == 16)
+                s->read_pos = 0;
+        }
+        if (s->read_count == 0) {
+            s->flags |= PL011_FLAG_RXFE;
+        }
+        if (s->read_count == s->read_trigger - 1)
+            s->int_level &= ~ PL011_INT_RX;
+        pl011_update(s);
+        return c;
+    case 1: /* UARTCR */
+        return 0;
+    case 6: /* UARTFR */
+        return s->flags;
+    case 8: /* UARTILPR */
+        return s->ilpr;
+    case 9: /* UARTIBRD */
+        return s->ibrd;
+    case 10: /* UARTFBRD */
+        return s->fbrd;
+    case 11: /* UARTLCR_H */
+        return s->lcr;
+    case 12: /* UARTCR */
+        return s->cr;
+    case 13: /* UARTIFLS */
+        return s->ifl;
+    case 14: /* UARTIMSC */
+        return s->int_enabled;
+    case 15: /* UARTRIS */
+        return s->int_level;
+    case 16: /* UARTMIS */
+        return s->int_level & s->int_enabled;
+    case 18: /* UARTDMACR */
+        return s->dmacr;
+    default:
+        cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset);
+        return 0;
+    }
+}
+
+static void pl011_set_read_trigger(pl011_state *s)
+{
+#if 0
+    /* The docs say the RX interrupt is triggered when the FIFO exceeds
+       the threshold.  However linux only reads the FIFO in response to an
+       interrupt.  Triggering the interrupt when the FIFO is non-empty seems
+       to make things work.  */
+    if (s->lcr & 0x10)
+        s->read_trigger = (s->ifl >> 1) & 0x1c;
+    else
+#endif
+        s->read_trigger = 1;
+}
+
+static void pl011_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    pl011_state *s = (pl011_state *)opaque;
+    unsigned char ch;
+
+    offset -= s->base;
+    switch (offset >> 2) {
+    case 0: /* UARTDR */
+        /* ??? Check if transmitter is enabled.  */
+        ch = value;
+        if (s->chr)
+            qemu_chr_write(s->chr, &ch, 1);
+        s->int_level |= PL011_INT_TX;
+        pl011_update(s);
+        break;
+    case 1: /* UARTCR */
+        s->cr = value;
+        break;
+    case 8: /* UARTUARTILPR */
+        s->ilpr = value;
+        break;
+    case 9: /* UARTIBRD */
+        s->ibrd = value;
+        break;
+    case 10: /* UARTFBRD */
+        s->fbrd = value;
+        break;
+    case 11: /* UARTLCR_H */
+        s->lcr = value;
+        pl011_set_read_trigger(s);
+        break;
+    case 12: /* UARTCR */
+        /* ??? Need to implement the enable and loopback bits.  */
+        s->cr = value;
+        break;
+    case 13: /* UARTIFS */
+        s->ifl = value;
+        pl011_set_read_trigger(s);
+        break;
+    case 14: /* UARTIMSC */
+        s->int_enabled = value;
+        pl011_update(s);
+        break;
+    case 17: /* UARTICR */
+        s->int_level &= ~value;
+        pl011_update(s);
+        break;
+    case 18: /* UARTDMACR */
+        s->dmacr = value;
+        if (value & 3)
+            cpu_abort(cpu_single_env, "PL011: DMA not implemented\n");
+        break;
+    default:
+        cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset);
+    }
+}
+
+static int pl011_can_recieve(void *opaque)
+{
+    pl011_state *s = (pl011_state *)opaque;
+
+    if (s->lcr & 0x10)
+        return s->read_count < 16;
+    else
+        return s->read_count < 1;
+}
+
+static void pl011_recieve(void *opaque, const uint8_t *buf, int size)
+{
+    pl011_state *s = (pl011_state *)opaque;
+    int slot;
+
+    slot = s->read_pos + s->read_count;
+    if (slot >= 16)
+        slot -= 16;
+    s->read_fifo[slot] = *buf;
+    s->read_count++;
+    s->flags &= ~PL011_FLAG_RXFE;
+    if (s->cr & 0x10 || s->read_count == 16) {
+        s->flags |= PL011_FLAG_RXFF;
+    }
+    if (s->read_count == s->read_trigger) {
+        s->int_level |= PL011_INT_RX;
+        pl011_update(s);
+    }
+}
+
+static void pl011_event(void *opaque, int event)
+{
+    /* ??? Should probably implement break.  */
+}
+
+static CPUReadMemoryFunc *pl011_readfn[] = {
+   pl011_read,
+   pl011_read,
+   pl011_read
+};
+
+static CPUWriteMemoryFunc *pl011_writefn[] = {
+   pl011_write,
+   pl011_write,
+   pl011_write
+};
+
+static void pl011_init(uint32_t base, icp_pic_state *pic, int irq,
+                       CharDriverState *chr)
+{
+    int iomemtype;
+    pl011_state *s;
+
+    s = (pl011_state *)qemu_mallocz(sizeof(pl011_state));
+    iomemtype = cpu_register_io_memory(0, pl011_readfn,
+                                       pl011_writefn, s);
+    cpu_register_physical_memory(base, 0x007fffff, 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_read_handler(chr, pl011_can_recieve, pl011_recieve, s);
+        qemu_chr_add_event_handler(chr, pl011_event);
+    }
+    /* ??? Save/restore.  */
+}
+
+/* CP control registers.  */
+typedef struct {
+    uint32_t base;
+} icp_control_state;
+
+static uint32_t icp_control_read(void *opaque, target_phys_addr_t offset)
+{
+    icp_control_state *s = (icp_control_state *)opaque;
+    offset -= s->base;
+    switch (offset >> 2) {
+    case 0: /* CP_IDFIELD */
+        return 0x41034003;
+    case 1: /* CP_FLASHPROG */
+        return 0;
+    case 2: /* CP_INTREG */
+        return 0;
+    case 3: /* CP_DECODE */
+        return 0x11;
+    default:
+        cpu_abort (cpu_single_env, "icp_control_read: Bad offset %x\n", offset);
+        return 0;
+    }
+}
+
+static void icp_control_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    icp_control_state *s = (icp_control_state *)opaque;
+    offset -= s->base;
+    switch (offset >> 2) {
+    case 1: /* CP_FLASHPROG */
+    case 2: /* CP_INTREG */
+    case 3: /* CP_DECODE */
+        /* Nothing interesting implemented yet.  */
+        break;
+    default:
+        cpu_abort (cpu_single_env, "icp_control_write: Bad offset %x\n", offset);
+    }
+}
+static CPUReadMemoryFunc *icp_control_readfn[] = {
+   icp_control_read,
+   icp_control_read,
+   icp_control_read
+};
+
+static CPUWriteMemoryFunc *icp_control_writefn[] = {
+   icp_control_write,
+   icp_control_write,
+   icp_control_write
+};
+
+static void icp_control_init(uint32_t base)
+{
+    int iomemtype;
+    icp_control_state *s;
+
+    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);
+    s->base = base;
+    /* ??? Save/restore.  */
+}
+
+
+/* Keyboard/Mouse Interface.  */
+
+typedef struct {
+    void *dev;
+    uint32_t base;
+    uint32_t cr;
+    uint32_t clk;
+    uint32_t last;
+    icp_pic_state *pic;
+    int pending;
+    int irq;
+    int is_mouse;
+} icp_kmi_state;
+
+static void icp_kmi_update(void *opaque, int level)
+{
+    icp_kmi_state *s = (icp_kmi_state *)opaque;
+    int raise;
+
+    s->pending = level;
+    raise = (s->pending && (s->cr & 0x10) != 0)
+            || (s->cr & 0x08) != 0;
+    pic_set_irq_new(s->pic, s->irq, raise);
+}
+
+static uint32_t icp_kmi_read(void *opaque, target_phys_addr_t offset)
+{
+    icp_kmi_state *s = (icp_kmi_state *)opaque;
+    offset -= s->base;
+    if (offset >= 0xfe0 && offset < 0x1000)
+        return 0;
+
+    switch (offset >> 2) {
+    case 0: /* KMICR */
+        return s->cr;
+    case 1: /* KMISTAT */
+        /* KMIC and KMID bits not implemented.  */
+        if (s->pending) {
+            return 0x10;
+        } else {
+            return 0;
+        }
+    case 2: /* KMIDATA */
+        if (s->pending)
+            s->last = ps2_read_data(s->dev);
+        return s->last;
+    case 3: /* KMICLKDIV */
+        return s->clk;
+    case 4: /* KMIIR */
+        return s->pending | 2;
+    default:
+        cpu_abort (cpu_single_env, "icp_kmi_read: Bad offset %x\n", offset);
+        return 0;
+    }
+}
+
+static void icp_kmi_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    icp_kmi_state *s = (icp_kmi_state *)opaque;
+    offset -= s->base;
+    switch (offset >> 2) {
+    case 0: /* KMICR */
+        s->cr = value;
+        icp_kmi_update(s, s->pending);
+        /* ??? Need to implement the enable/disable bit.  */
+        break;
+    case 2: /* KMIDATA */
+        /* ??? This should toggle the TX interrupt line.  */
+        /* ??? This means kbd/mouse can block each other.  */
+        if (s->is_mouse) {
+            ps2_write_mouse(s->dev, value);
+        } else {
+            ps2_write_keyboard(s->dev, value);
+        }
+        break;
+    case 3: /* KMICLKDIV */
+        s->clk = value;
+        return;
+    default:
+        cpu_abort (cpu_single_env, "icp_kmi_write: Bad offset %x\n", offset);
+    }
+}
+static CPUReadMemoryFunc *icp_kmi_readfn[] = {
+   icp_kmi_read,
+   icp_kmi_read,
+   icp_kmi_read
+};
+
+static CPUWriteMemoryFunc *icp_kmi_writefn[] = {
+   icp_kmi_write,
+   icp_kmi_write,
+   icp_kmi_write
+};
+
+static void icp_kmi_init(uint32_t base, icp_pic_state * pic, int irq,
+                         int is_mouse)
+{
+    int iomemtype;
+    icp_kmi_state *s;
+
+    s = (icp_kmi_state *)qemu_mallocz(sizeof(icp_kmi_state));
+    iomemtype = cpu_register_io_memory(0, icp_kmi_readfn,
+                                       icp_kmi_writefn, s);
+    cpu_register_physical_memory(base, 0x007fffff, iomemtype);
+    s->base = base;
+    s->pic = pic;
+    s->irq = irq;
+    s->is_mouse = is_mouse;
+    if (is_mouse)
+        s->dev = ps2_mouse_init(icp_kmi_update, s);
+    else
+        s->dev = ps2_kbd_init(icp_kmi_update, s);
+    /* ??? Save/restore.  */
+}
+
+/* The worlds second smallest bootloader.  Set r0-r2, then jump to kernel.  */
+static uint32_t bootloader[] = {
+  0xe3a00000, /* mov     r0, #0 */
+  0xe3a01013, /* mov     r1, #0x13 */
+  0xe3811c01, /* orr     r1, r1, #0x100 */
+  0xe59f2000, /* ldr     r2, [pc, #0] */
+  0xe59ff000, /* ldr     pc, [pc, #0] */
+  0, /* Address of kernel args.  Set by integratorcp_init.  */
+  0  /* Kernel entry point.  Set by integratorcp_init.  */
+};
+
+static void set_kernel_args(uint32_t ram_size, int initrd_size,
+                            const char *kernel_cmdline)
+{
+    uint32_t *p;
+
+    p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR);
+    /* ATAG_CORE */
+    *(p++) = 5;
+    *(p++) = 0x54410001;
+    *(p++) = 1;
+    *(p++) = 0x1000;
+    *(p++) = 0;
+    /* ATAG_MEM */
+    *(p++) = 4;
+    *(p++) = 0x54410002;
+    *(p++) = ram_size;
+    *(p++) = 0;
+    if (initrd_size) {
+        /* ATAG_INITRD2 */
+        *(p++) = 4;
+        *(p++) = 0x54420005;
+        *(p++) = INITRD_LOAD_ADDR;
+        *(p++) = initrd_size;
+    }
+    if (kernel_cmdline && *kernel_cmdline) {
+        /* ATAG_CMDLINE */
+        int cmdline_size;
+
+        cmdline_size = strlen(kernel_cmdline);
+        memcpy (p + 2, kernel_cmdline, cmdline_size + 1);
+        cmdline_size = (cmdline_size >> 2) + 1;
+        *(p++) = cmdline_size + 2;
+        *(p++) = 0x54410009;
+        p += cmdline_size;
+    }
+    /* ATAG_END */
+    *(p++) = 0;
+    *(p++) = 0;
+}
+
+/* Board init.  */
+
+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)
+{
+    CPUState *env;
+    uint32_t bios_offset;
+    icp_pic_state *pic;
+    int kernel_size;
+    int initrd_size;
+
+    env = cpu_init();
+    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.  */
+    /* SDRAM at address zero*/
+    cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+    /* And again at address 0x80000000 */
+    cpu_register_physical_memory(0x80000000, ram_size, IO_MEM_RAM);
+
+    integratorcm_init(ram_size >> 20, bios_offset);
+    pic = icp_pic_init(0x14000000, env, -1);
+    icp_pic_init(0xca000000, pic, 26);
+    icp_pit_init(0x13000000, pic);
+    pl011_init(0x16000000, pic, 1, serial_hds[0]);
+    pl011_init(0x17000000, pic, 2, serial_hds[1]);
+    icp_control_init(0xcb000000);
+    icp_kmi_init(0x18000000, pic, 3, 0);
+    icp_kmi_init(0x19000000, pic, 4, 1);
+    if (nd_table[0].vlan)
+        smc91c111_init(&nd_table[0], 0xc8000000, pic, 27);
+
+    /* Load the kernel.  */
+    if (!kernel_filename) {
+        fprintf(stderr, "Kernel image must be specified\n");
+        exit(1);
+    }
+    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);
+        if (initrd_size < 0) {
+            fprintf(stderr, "qemu: could not load initrd '%s'\n",
+                    initrd_filename);
+            exit(1);
+        }
+    } else {
+        initrd_size = 0;
+    }
+    bootloader[5] = KERNEL_ARGS_ADDR;
+    bootloader[6] = KERNEL_LOAD_ADDR;
+    memcpy(phys_ram_base, bootloader, sizeof(bootloader));
+    set_kernel_args(ram_size, initrd_size, kernel_cmdline);
+}
+
+QEMUMachine integratorcp_machine = {
+    "integratorcp",
+    "ARM Integrator/CP",
+    integratorcp_init,
+};
index d0b16ea..e7d96c8 100644 (file)
@@ -33,9 +33,11 @@ do { printf("IOMMU: " fmt , ##args); } while (0)
 #define DPRINTF(fmt, args...)
 #endif
 
-#define IOMMU_NREGS (3*4096)
+#define IOMMU_NREGS (3*4096/4)
+#define IOMMU_CTRL          (0x0000 >> 2)
 #define IOMMU_CTRL_IMPL     0xf0000000 /* Implementation */
 #define IOMMU_CTRL_VERS     0x0f000000 /* Version */
+#define IOMMU_VERSION       0x04000000
 #define IOMMU_CTRL_RNGE     0x0000001c /* Mapping RANGE */
 #define IOMMU_RNGE_16MB     0x00000000 /* 0xff000000 -> 0xffffffff */
 #define IOMMU_RNGE_32MB     0x00000004 /* 0xfe000000 -> 0xffffffff */
@@ -46,6 +48,32 @@ do { printf("IOMMU: " fmt , ##args); } while (0)
 #define IOMMU_RNGE_1GB      0x00000018 /* 0xc0000000 -> 0xffffffff */
 #define IOMMU_RNGE_2GB      0x0000001c /* 0x80000000 -> 0xffffffff */
 #define IOMMU_CTRL_ENAB     0x00000001 /* IOMMU Enable */
+#define IOMMU_CTRL_MASK     0x0000001d
+
+#define IOMMU_BASE          (0x0004 >> 2)
+#define IOMMU_BASE_MASK     0x07fffc00
+
+#define IOMMU_TLBFLUSH      (0x0014 >> 2)
+#define IOMMU_TLBFLUSH_MASK 0xffffffff
+
+#define IOMMU_PGFLUSH       (0x0018 >> 2)
+#define IOMMU_PGFLUSH_MASK  0xffffffff
+
+#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 */
+#define IOMMU_SBCFG3        (0x101c >> 2) /* SBUS configration per-slot */
+#define IOMMU_SBCFG_SAB30   0x00010000 /* Phys-address bit 30 when bypass enabled */
+#define IOMMU_SBCFG_BA16    0x00000004 /* Slave supports 16 byte bursts */
+#define IOMMU_SBCFG_BA8     0x00000002 /* Slave supports 8 byte bursts */
+#define IOMMU_SBCFG_BYPASS  0x00000001 /* Bypass IOMMU, treat all addresses
+                                                 produced by this device as pure
+                                          physical. */
+#define IOMMU_SBCFG_MASK    0x00010003
+
+#define IOMMU_ARBEN         (0x2000 >> 2) /* SBUS arbitration enable */
+#define IOMMU_ARBEN_MASK    0x001f0000
+#define IOMMU_MID           0x00000008
 
 /* The format of an iopte in the page tables */
 #define IOPTE_PAGE          0x07ffff00 /* Physical page number (PA[30:12]) */
@@ -87,7 +115,7 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val
     saddr = (addr - s->addr) >> 2;
     DPRINTF("write reg[%d] = %x\n", saddr, val);
     switch (saddr) {
-    case 0:
+    case IOMMU_CTRL:
        switch (val & IOMMU_CTRL_RNGE) {
        case IOMMU_RNGE_16MB:
            s->iostart = 0xff000000;
@@ -116,7 +144,30 @@ static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val
            break;
        }
        DPRINTF("iostart = %x\n", s->iostart);
-       /* Fall through */
+       s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | IOMMU_VERSION);
+       break;
+    case IOMMU_BASE:
+       s->regs[saddr] = val & IOMMU_BASE_MASK;
+       break;
+    case IOMMU_TLBFLUSH:
+       DPRINTF("tlb flush %x\n", val);
+       s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK;
+       break;
+    case IOMMU_PGFLUSH:
+       DPRINTF("page flush %x\n", val);
+       s->regs[saddr] = val & IOMMU_PGFLUSH_MASK;
+       break;
+    case IOMMU_SBCFG0:
+    case IOMMU_SBCFG1:
+    case IOMMU_SBCFG2:
+    case IOMMU_SBCFG3:
+       s->regs[saddr] = val & IOMMU_SBCFG_MASK;
+       break;
+    case IOMMU_ARBEN:
+        // XXX implement SBus probing: fault when reading unmapped
+        // addresses, fault cause and address stored to MMU/IOMMU
+       s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID;
+       break;
     default:
        s->regs[saddr] = val;
        break;
@@ -143,8 +194,7 @@ uint32_t iommu_translate_local(void *opaque, uint32_t addr)
     iopte = s->regs[1] << 4;
     addr &= ~s->iostart;
     iopte += (addr >> (PAGE_SHIFT - 2)) & ~3;
-    cpu_physical_memory_read(iopte, (void *) &pa, 4);
-    bswap32s(&pa);
+    pa = ldl_phys(iopte);
     tmppte = pa;
     pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK);
     DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte);
@@ -184,6 +234,7 @@ static void iommu_reset(void *opaque)
 
     memset(s->regs, 0, IOMMU_NREGS * 4);
     s->iostart = 0;
+    s->regs[0] = IOMMU_VERSION;
 }
 
 void *iommu_init(uint32_t addr)
index 3a8a7d0..2fef6b1 100644 (file)
@@ -154,7 +154,8 @@ struct lance_init_block {
 #define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1)
 
 typedef struct LANCEState {
-    NetDriverState *nd;
+    VLANClientState *vc;
+    uint8_t macaddr[6]; /* init mac address */
     uint32_t leptr;
     uint16_t addr;
     uint16_t regs[LE_NREGS];
@@ -169,7 +170,7 @@ static void lance_send(void *opaque);
 static void lance_reset(void *opaque)
 {
     LANCEState *s = opaque;
-    memcpy(s->phys, s->nd->macaddr, 6);
+    memcpy(s->phys, s->macaddr, 6);
     s->rxptr = 0;
     s->txptr = 0;
     memset(s->regs, 0, LE_NREGS * 2);
@@ -280,31 +281,6 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = {
 };
 
 
-/* return the max buffer size if the LANCE can receive more data */
-static int lance_can_receive(void *opaque)
-{
-    LANCEState *s = opaque;
-    uint32_t dmaptr = s->leptr + s->ledmaregs[3];
-    struct lance_init_block *ib;
-    int i;
-    uint8_t temp8;
-
-    if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
-       return 0;
-
-    ib = (void *) iommu_translate(dmaptr);
-
-    for (i = 0; i < RX_RING_SIZE; i++) {
-       cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1);
-       if (temp8 == (LE_R1_OWN)) {
-           DPRINTF("can receive %d\n", RX_BUFF_SIZE);
-           return RX_BUFF_SIZE;
-       }
-    }
-    DPRINTF("cannot receive\n");
-    return 0;
-}
-
 #define MIN_BUF_SIZE 60
 
 static void lance_receive(void *opaque, const uint8_t *buf, int size)
@@ -368,7 +344,7 @@ static void lance_send(void *opaque)
            temp16 = (~temp16) + 1;
            cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp16);
            DPRINTF("sending packet, len %d\n", temp16);
-           qemu_send_packet(s->nd, pkt_buf, temp16);
+           qemu_send_packet(s->vc, pkt_buf, temp16);
            temp8 = LE_T1_POK;
            cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1);
            s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK;
@@ -443,7 +419,7 @@ static int lance_load(QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
+void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
 {
     LANCEState *s;
     int lance_io_memory, ledma_io_memory;
@@ -452,7 +428,6 @@ void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
     if (!s)
         return;
 
-    s->nd = nd;
     s->irq = irq;
 
     lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
@@ -461,8 +436,21 @@ void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
     ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s);
     cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
 
+    memcpy(s->macaddr, nd->macaddr, 6);
+
     lance_reset(s);
-    qemu_add_read_packet(nd, lance_can_receive, lance_receive, s);
+
+    s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, s);
+
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "lance 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]);
+
     register_savevm("lance", leaddr, 1, lance_save, lance_load, s);
     qemu_register_reset(lance_reset, s);
 }
diff --git a/qemu/hw/m48t08.c b/qemu/hw/m48t08.c
deleted file mode 100644 (file)
index 0945879..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * QEMU M48T08 NVRAM emulation for Sparc platform
- * 
- * Copyright (c) 2003-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
- * 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 "m48t08.h"
-
-//#define DEBUG_NVRAM
-
-#if defined(DEBUG_NVRAM)
-#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
-#else
-#define NVRAM_PRINTF(fmt, args...) do { } while (0)
-#endif
-
-#define NVRAM_MAX_MEM 0x1ff0
-#define NVRAM_MAXADDR 0x1fff
-
-struct m48t08_t {
-    /* RTC management */
-    time_t   time_offset;
-    time_t   stop_time;
-    /* NVRAM storage */
-    uint8_t *buffer;
-};
-
-/* Fake timer functions */
-/* Generic helpers for BCD */
-static inline uint8_t toBCD (uint8_t value)
-{
-    return (((value / 10) % 10) << 4) | (value % 10);
-}
-
-static inline uint8_t fromBCD (uint8_t BCD)
-{
-    return ((BCD >> 4) * 10) + (BCD & 0x0F);
-}
-
-/* RTC management helpers */
-static void get_time (m48t08_t *NVRAM, struct tm *tm)
-{
-    time_t t;
-
-    t = time(NULL) + NVRAM->time_offset;
-#ifdef _WIN32
-    memcpy(tm,localtime(&t),sizeof(*tm));
-#else
-    localtime_r (&t, tm) ;
-#endif
-}
-
-static void set_time (m48t08_t *NVRAM, struct tm *tm)
-{
-    time_t now, new_time;
-    
-    new_time = mktime(tm);
-    now = time(NULL);
-    NVRAM->time_offset = new_time - now;
-}
-
-/* Direct access to NVRAM */
-void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val)
-{
-    struct tm tm;
-    int tmp;
-
-    addr &= NVRAM_MAXADDR;
-    switch (addr) {
-    case 0x1FF8:
-        /* control */
-       NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
-        break;
-    case 0x1FF9:
-        /* seconds (BCD) */
-       tmp = fromBCD(val & 0x7F);
-       if (tmp >= 0 && tmp <= 59) {
-           get_time(NVRAM, &tm);
-           tm.tm_sec = tmp;
-           set_time(NVRAM, &tm);
-       }
-       if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
-           if (val & 0x80) {
-               NVRAM->stop_time = time(NULL);
-           } else {
-               NVRAM->time_offset += NVRAM->stop_time - time(NULL);
-               NVRAM->stop_time = 0;
-           }
-       }
-       NVRAM->buffer[0x1FF9] = val & 0x80;
-        break;
-    case 0x1FFA:
-        /* minutes (BCD) */
-       tmp = fromBCD(val & 0x7F);
-       if (tmp >= 0 && tmp <= 59) {
-           get_time(NVRAM, &tm);
-           tm.tm_min = tmp;
-           set_time(NVRAM, &tm);
-       }
-        break;
-    case 0x1FFB:
-        /* hours (BCD) */
-       tmp = fromBCD(val & 0x3F);
-       if (tmp >= 0 && tmp <= 23) {
-           get_time(NVRAM, &tm);
-           tm.tm_hour = tmp;
-           set_time(NVRAM, &tm);
-       }
-        break;
-    case 0x1FFC:
-        /* day of the week / century */
-       tmp = fromBCD(val & 0x07);
-       get_time(NVRAM, &tm);
-       tm.tm_wday = tmp;
-       set_time(NVRAM, &tm);
-        NVRAM->buffer[0x1FFC] = val & 0x40;
-        break;
-    case 0x1FFD:
-        /* date */
-       tmp = fromBCD(val & 0x1F);
-       if (tmp != 0) {
-           get_time(NVRAM, &tm);
-           tm.tm_mday = tmp;
-           set_time(NVRAM, &tm);
-       }
-        break;
-    case 0x1FFE:
-        /* month */
-       tmp = fromBCD(val & 0x1F);
-       if (tmp >= 1 && tmp <= 12) {
-           get_time(NVRAM, &tm);
-           tm.tm_mon = tmp - 1;
-           set_time(NVRAM, &tm);
-       }
-        break;
-    case 0x1FFF:
-        /* year */
-       tmp = fromBCD(val);
-       if (tmp >= 0 && tmp <= 99) {
-           get_time(NVRAM, &tm);
-           tm.tm_year = fromBCD(val);
-           set_time(NVRAM, &tm);
-       }
-        break;
-    default:
-       NVRAM->buffer[addr] = val & 0xFF;
-        break;
-    }
-}
-
-uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr)
-{
-    struct tm tm;
-    uint8_t retval = 0xFF;
-
-    addr &= NVRAM_MAXADDR;
-    switch (addr) {
-    case 0x1FF8:
-        /* control */
-       goto do_read;
-    case 0x1FF9:
-        /* seconds (BCD) */
-        get_time(NVRAM, &tm);
-        retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
-        break;
-    case 0x1FFA:
-        /* minutes (BCD) */
-        get_time(NVRAM, &tm);
-        retval = toBCD(tm.tm_min);
-        break;
-    case 0x1FFB:
-        /* hours (BCD) */
-        get_time(NVRAM, &tm);
-        retval = toBCD(tm.tm_hour);
-        break;
-    case 0x1FFC:
-        /* day of the week / century */
-        get_time(NVRAM, &tm);
-        retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
-        break;
-    case 0x1FFD:
-        /* date */
-        get_time(NVRAM, &tm);
-        retval = toBCD(tm.tm_mday);
-        break;
-    case 0x1FFE:
-        /* month */
-        get_time(NVRAM, &tm);
-        retval = toBCD(tm.tm_mon + 1);
-        break;
-    case 0x1FFF:
-        /* year */
-        get_time(NVRAM, &tm);
-        retval = toBCD(tm.tm_year);
-        break;
-    default:
-    do_read:
-       retval = NVRAM->buffer[addr];
-        break;
-    }
-    return retval;
-}
-
-static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-    m48t08_t *NVRAM = opaque;
-    
-    m48t08_write(NVRAM, addr, value);
-}
-
-static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-    m48t08_t *NVRAM = opaque;
-    
-    m48t08_write(NVRAM, addr, value);
-    m48t08_write(NVRAM, addr + 1, value >> 8);
-}
-
-static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-    m48t08_t *NVRAM = opaque;
-    
-    m48t08_write(NVRAM, addr, value);
-    m48t08_write(NVRAM, addr + 1, value >> 8);
-    m48t08_write(NVRAM, addr + 2, value >> 16);
-    m48t08_write(NVRAM, addr + 3, value >> 24);
-}
-
-static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
-{
-    m48t08_t *NVRAM = opaque;
-    uint32_t retval = 0;
-    
-    retval = m48t08_read(NVRAM, addr);
-    return retval;
-}
-
-static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
-{
-    m48t08_t *NVRAM = opaque;
-    uint32_t retval = 0;
-    
-    retval = m48t08_read(NVRAM, addr) << 8;
-    retval |= m48t08_read(NVRAM, addr + 1);
-    return retval;
-}
-
-static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
-{
-    m48t08_t *NVRAM = opaque;
-    uint32_t retval = 0;
-    
-    retval = m48t08_read(NVRAM, addr) << 24;
-    retval |= m48t08_read(NVRAM, addr + 1) << 16;
-    retval |= m48t08_read(NVRAM, addr + 2) << 8;
-    retval |= m48t08_read(NVRAM, addr + 3);
-    return retval;
-}
-
-static CPUWriteMemoryFunc *nvram_write[] = {
-    &nvram_writeb,
-    &nvram_writew,
-    &nvram_writel,
-};
-
-static CPUReadMemoryFunc *nvram_read[] = {
-    &nvram_readb,
-    &nvram_readw,
-    &nvram_readl,
-};
-
-static void nvram_save(QEMUFile *f, void *opaque)
-{
-    m48t08_t *s = opaque;
-    
-    qemu_put_be32s(f, (uint32_t *)&s->time_offset);
-    qemu_put_be32s(f, (uint32_t *)&s->stop_time);
-    qemu_put_buffer(f, s->buffer, 0x2000);
-}
-
-static int nvram_load(QEMUFile *f, void *opaque, int version_id)
-{
-    m48t08_t *s = opaque;
-    
-    if (version_id != 1)
-        return -EINVAL;
-
-    qemu_get_be32s(f, (uint32_t *)&s->time_offset);
-    qemu_get_be32s(f, (uint32_t *)&s->stop_time);
-    qemu_get_buffer(f, s->buffer, 0x2000);
-    return 0;
-}
-
-static void m48t08_reset(void *opaque)
-{
-    m48t08_t *s = opaque;
-
-    s->time_offset = 0;
-    s->stop_time = 0;
-}
-
-
-/* Initialisation routine */
-m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size)
-{
-    m48t08_t *s;
-    int mem_index;
-
-    s = qemu_mallocz(sizeof(m48t08_t));
-    if (!s)
-       return NULL;
-    s->buffer = qemu_mallocz(size);
-    if (!s->buffer) {
-        qemu_free(s);
-        return NULL;
-    }
-    if (mem_base != 0) {
-        mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
-        cpu_register_physical_memory(mem_base, 0x2000, mem_index);
-    }
-
-    register_savevm("nvram", mem_base, 1, nvram_save, nvram_load, s);
-    qemu_register_reset(m48t08_reset, s);
-    return s;
-}
-
-#if 0
-struct idprom
-{
-        unsigned char   id_format;      /* Format identifier (always 0x01) */
-        unsigned char   id_machtype;    /* Machine type */
-        unsigned char   id_ethaddr[6];  /* Hardware ethernet address */
-        long            id_date;        /* Date of manufacture */
-        unsigned int    id_sernum:24;   /* Unique serial number */
-        unsigned char   id_cksum;       /* Checksum - xor of the data bytes */
-        unsigned char   reserved[16];
-};
-#endif
diff --git a/qemu/hw/m48t08.h b/qemu/hw/m48t08.h
deleted file mode 100644 (file)
index 985116a..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#if !defined (__M48T08_H__)
-#define __M48T08_H__
-
-typedef struct m48t08_t m48t08_t;
-
-void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val);
-uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr);
-m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size);
-
-#endif /* !defined (__M48T08_H__) */
index 5ab5816..81e64e4 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * QEMU M48T59 NVRAM emulation for PPC PREP platform
+ * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
  * 
- * Copyright (c) 2003-2004 Jocelyn Mayer
+ * Copyright (c) 2003-2005 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
 #define NVRAM_PRINTF(fmt, args...) do { } while (0)
 #endif
 
+/*
+ * The M48T08 and M48T59 chips are very similar. The newer '59 has
+ * alarm and a watchdog timer and related control registers. In the
+ * PPC platform there is also a nvram lock function.
+ */
 struct m48t59_t {
+    /* Model parameters */
+    int type; // 8 = m48t08, 59 = m48t59
     /* Hardware parameters */
     int      IRQ;
     int mem_index;
@@ -188,14 +195,17 @@ static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value)
 }
 
 /* Direct access to NVRAM */
-void m48t59_write (m48t59_t *NVRAM, uint32_t val)
+void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val)
 {
     struct tm tm;
     int tmp;
 
-    if (NVRAM->addr > 0x1FF8 && NVRAM->addr < 0x2000)
-       NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val);
-    switch (NVRAM->addr) {
+    if (addr > 0x1FF8 && addr < 0x2000)
+       NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
+    if (NVRAM->type == 8 && 
+        (addr >= 0x1ff0 && addr <= 0x1ff7))
+        goto do_write;
+    switch (addr) {
     case 0x1FF0:
         /* flags register : read-only */
         break;
@@ -204,52 +214,52 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t val)
         break;
     case 0x1FF2:
         /* alarm seconds */
-       tmp = fromBCD(val & 0x7F);
-       if (tmp >= 0 && tmp <= 59) {
-           get_alarm(NVRAM, &tm);
-           tm.tm_sec = tmp;
-           NVRAM->buffer[0x1FF2] = val;
-           set_alarm(NVRAM, &tm);
-       }
+        tmp = fromBCD(val & 0x7F);
+        if (tmp >= 0 && tmp <= 59) {
+            get_alarm(NVRAM, &tm);
+            tm.tm_sec = tmp;
+            NVRAM->buffer[0x1FF2] = val;
+            set_alarm(NVRAM, &tm);
+        }
         break;
     case 0x1FF3:
         /* alarm minutes */
-       tmp = fromBCD(val & 0x7F);
-       if (tmp >= 0 && tmp <= 59) {
-           get_alarm(NVRAM, &tm);
-           tm.tm_min = tmp;
-           NVRAM->buffer[0x1FF3] = val;
-           set_alarm(NVRAM, &tm);
-       }
+        tmp = fromBCD(val & 0x7F);
+        if (tmp >= 0 && tmp <= 59) {
+            get_alarm(NVRAM, &tm);
+            tm.tm_min = tmp;
+            NVRAM->buffer[0x1FF3] = val;
+            set_alarm(NVRAM, &tm);
+        }
         break;
     case 0x1FF4:
         /* alarm hours */
-       tmp = fromBCD(val & 0x3F);
-       if (tmp >= 0 && tmp <= 23) {
-           get_alarm(NVRAM, &tm);
-           tm.tm_hour = tmp;
-           NVRAM->buffer[0x1FF4] = val;
-           set_alarm(NVRAM, &tm);
-       }
+        tmp = fromBCD(val & 0x3F);
+        if (tmp >= 0 && tmp <= 23) {
+            get_alarm(NVRAM, &tm);
+            tm.tm_hour = tmp;
+            NVRAM->buffer[0x1FF4] = val;
+            set_alarm(NVRAM, &tm);
+        }
         break;
     case 0x1FF5:
         /* alarm date */
-       tmp = fromBCD(val & 0x1F);
-       if (tmp != 0) {
-           get_alarm(NVRAM, &tm);
-           tm.tm_mday = tmp;
-           NVRAM->buffer[0x1FF5] = val;
-           set_alarm(NVRAM, &tm);
-       }
+        tmp = fromBCD(val & 0x1F);
+        if (tmp != 0) {
+            get_alarm(NVRAM, &tm);
+            tm.tm_mday = tmp;
+            NVRAM->buffer[0x1FF5] = val;
+            set_alarm(NVRAM, &tm);
+        }
         break;
     case 0x1FF6:
         /* interrupts */
-       NVRAM->buffer[0x1FF6] = val;
+        NVRAM->buffer[0x1FF6] = val;
         break;
     case 0x1FF7:
         /* watchdog */
-       NVRAM->buffer[0x1FF7] = val;
-       set_up_watchdog(NVRAM, val);
+        NVRAM->buffer[0x1FF7] = val;
+        set_up_watchdog(NVRAM, val);
         break;
     case 0x1FF8:
         /* control */
@@ -328,24 +338,27 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t val)
         break;
     default:
         /* Check lock registers state */
-        if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
+        if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
             break;
-        if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
+        if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
             break;
-        if (NVRAM->addr < 0x1FF0 ||
-           (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
-            NVRAM->buffer[NVRAM->addr] = val & 0xFF;
+    do_write:
+        if (addr < NVRAM->size) {
+            NVRAM->buffer[addr] = val & 0xFF;
        }
         break;
     }
 }
 
-uint32_t m48t59_read (m48t59_t *NVRAM)
+uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr)
 {
     struct tm tm;
     uint32_t retval = 0xFF;
 
-    switch (NVRAM->addr) {
+    if (NVRAM->type == 8 && 
+        (addr >= 0x1ff0 && addr <= 0x1ff7))
+        goto do_read;
+    switch (addr) {
     case 0x1FF0:
         /* flags register */
        goto do_read;
@@ -412,19 +425,18 @@ uint32_t m48t59_read (m48t59_t *NVRAM)
         break;
     default:
         /* Check lock registers state */
-        if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
+        if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
             break;
-        if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
+        if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
             break;
-        if (NVRAM->addr < 0x1FF0 ||
-           (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
-       do_read:
-            retval = NVRAM->buffer[NVRAM->addr];
+    do_read:
+        if (addr < NVRAM->size) {
+            retval = NVRAM->buffer[addr];
        }
         break;
     }
-    if (NVRAM->addr > 0x1FF9 && NVRAM->addr < 0x2000)
-       NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval);
+    if (addr > 0x1FF9 && addr < 0x2000)
+       NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
 
     return retval;
 }
@@ -456,7 +468,7 @@ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
         NVRAM->addr |= val << 8;
         break;
     case 3:
-        m48t59_write(NVRAM, val);
+        m48t59_write(NVRAM, val, NVRAM->addr);
         NVRAM->addr = 0x0000;
         break;
     default:
@@ -472,7 +484,7 @@ static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
     addr -= NVRAM->io_base;
     switch (addr) {
     case 3:
-        retval = m48t59_read(NVRAM);
+        retval = m48t59_read(NVRAM, NVRAM->addr);
         break;
     default:
         retval = -1;
@@ -488,8 +500,7 @@ static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
     m48t59_t *NVRAM = opaque;
     
     addr -= NVRAM->mem_base;
-    if (addr < 0x1FF0)
-        NVRAM->buffer[addr] = value;
+    m48t59_write(NVRAM, addr, value & 0xff);
 }
 
 static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
@@ -497,10 +508,8 @@ static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
     m48t59_t *NVRAM = opaque;
     
     addr -= NVRAM->mem_base;
-    if (addr < 0x1FF0) {
-        NVRAM->buffer[addr] = value >> 8;
-        NVRAM->buffer[addr + 1] = value;
-    }
+    m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
+    m48t59_write(NVRAM, addr + 1, value & 0xff);
 }
 
 static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
@@ -508,53 +517,43 @@ static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
     m48t59_t *NVRAM = opaque;
     
     addr -= NVRAM->mem_base;
-    if (addr < 0x1FF0) {
-        NVRAM->buffer[addr] = value >> 24;
-        NVRAM->buffer[addr + 1] = value >> 16;
-        NVRAM->buffer[addr + 2] = value >> 8;
-        NVRAM->buffer[addr + 3] = value;
-    }
+    m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
+    m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
+    m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
+    m48t59_write(NVRAM, addr + 3, value & 0xff);
 }
 
 static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
 {
     m48t59_t *NVRAM = opaque;
-    uint32_t retval = 0;
+    uint32_t retval;
     
     addr -= NVRAM->mem_base;
-    if (addr < 0x1FF0)
-        retval = NVRAM->buffer[addr];
-
+    retval = m48t59_read(NVRAM, addr);
     return retval;
 }
 
 static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
 {
     m48t59_t *NVRAM = opaque;
-    uint32_t retval = 0;
+    uint32_t retval;
     
     addr -= NVRAM->mem_base;
-    if (addr < 0x1FF0) {
-        retval = NVRAM->buffer[addr] << 8;
-        retval |= NVRAM->buffer[addr + 1];
-    }
-
+    retval = m48t59_read(NVRAM, addr) << 8;
+    retval |= m48t59_read(NVRAM, addr + 1);
     return retval;
 }
 
 static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
 {
     m48t59_t *NVRAM = opaque;
-    uint32_t retval = 0;
-    
-    addr -= NVRAM->mem_base;
-    if (addr < 0x1FF0) {
-        retval = NVRAM->buffer[addr] << 24;
-        retval |= NVRAM->buffer[addr + 1] << 16;
-        retval |= NVRAM->buffer[addr + 2] << 8;
-        retval |= NVRAM->buffer[addr + 3];
-    }
+    uint32_t retval;
 
+    addr -= NVRAM->mem_base;
+    retval = m48t59_read(NVRAM, addr) << 24;
+    retval |= m48t59_read(NVRAM, addr + 1) << 16;
+    retval |= m48t59_read(NVRAM, addr + 2) << 8;
+    retval |= m48t59_read(NVRAM, addr + 3);
     return retval;
 }
 
@@ -569,9 +568,11 @@ static CPUReadMemoryFunc *nvram_read[] = {
     &nvram_readw,
     &nvram_readl,
 };
+
 /* Initialisation routine */
-m48t59_t *m48t59_init (int IRQ, uint32_t mem_base,
-                       uint32_t io_base, uint16_t size)
+m48t59_t *m48t59_init (int IRQ, target_ulong mem_base,
+                       uint32_t io_base, uint16_t size,
+                       int type)
 {
     m48t59_t *s;
 
@@ -588,14 +589,19 @@ m48t59_t *m48t59_init (int IRQ, uint32_t mem_base,
     s->mem_base = mem_base;
     s->io_base = io_base;
     s->addr = 0;
-    register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
-    register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
+    s->type = type;
+    if (io_base != 0) {
+        register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
+        register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
+    }
     if (mem_base != 0) {
         s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
         cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
     }
-    s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);
-    s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
+    if (type == 59) {
+        s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);
+        s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
+    }
     s->lock = 0;
 
     return s;
index 03d8ea3..af22dc1 100644 (file)
@@ -3,11 +3,11 @@
 
 typedef struct m48t59_t m48t59_t;
 
-void m48t59_write (m48t59_t *NVRAM, uint32_t val);
-uint32_t m48t59_read (m48t59_t *NVRAM);
-void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr);
+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, uint32_t io_base,
-                       uint32_t mem_base, uint16_t size);
+m48t59_t *m48t59_init (int IRQ, target_ulong mem_base,
+                       uint32_t io_base, uint16_t size,
+                       int type);
 
 #endif /* !defined (__M48T59_H__) */
index bf3376d..5f51f87 100644 (file)
@@ -11,12 +11,13 @@ static PITState *pit;
 
 static void pic_irq_request(void *opaque, int level)
 {
+    CPUState *env = first_cpu;
     if (level) {
-        cpu_single_env->CP0_Cause |= 0x00000400;
-        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+        env->CP0_Cause |= 0x00000400;
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
     } else {
-       cpu_single_env->CP0_Cause &= ~0x00000400;
-        cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+       env->CP0_Cause &= ~0x00000400;
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
     }
 }
 
@@ -52,7 +53,7 @@ static void cpu_mips_update_count (CPUState *env, uint32_t count,
     next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000);
     if (next == now)
        next++;
-#if 1
+#if 0
     if (logfile) {
         fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n",
                 __func__, now, count, compare, next - now);
@@ -74,8 +75,8 @@ void cpu_mips_store_count (CPUState *env, uint32_t value)
 void cpu_mips_store_compare (CPUState *env, uint32_t value)
 {
     cpu_mips_update_count(env, cpu_mips_get_count(env), value);
-    cpu_single_env->CP0_Cause &= ~0x00008000;
-    cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+    env->CP0_Cause &= ~0x00008000;
+    cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
 }
 
 static void mips_timer_cb (void *opaque)
@@ -83,14 +84,14 @@ static void mips_timer_cb (void *opaque)
     CPUState *env;
 
     env = opaque;
-#if 1
+#if 0
     if (logfile) {
         fprintf(logfile, "%s\n", __func__);
     }
 #endif
     cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare);
-    cpu_single_env->CP0_Cause |= 0x00008000;
-    cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+    env->CP0_Cause |= 0x00008000;
+    cpu_interrupt(env, CPU_INTERRUPT_HARD);
 }
 
 void cpu_mips_clock_init (CPUState *env)
@@ -102,23 +103,29 @@ void cpu_mips_clock_init (CPUState *env)
 
 static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
 {
+#if 0
     if (logfile)
         fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
+#endif
     cpu_outb(NULL, addr & 0xffff, value);
 }
 
 static uint32_t io_readb (void *opaque, target_phys_addr_t addr)
 {
     uint32_t ret = cpu_inb(NULL, addr & 0xffff);
+#if 0
     if (logfile)
         fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
+#endif
     return ret;
 }
 
 static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
 {
+#if 0
     if (logfile)
         fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
+#endif
 #ifdef TARGET_WORDS_BIGENDIAN
     value = bswap16(value);
 #endif
@@ -131,15 +138,19 @@ static uint32_t io_readw (void *opaque, target_phys_addr_t addr)
 #ifdef TARGET_WORDS_BIGENDIAN
     ret = bswap16(ret);
 #endif
+#if 0
     if (logfile)
         fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
+#endif
     return ret;
 }
 
 static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
 {
+#if 0
     if (logfile)
         fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
+#endif
 #ifdef TARGET_WORDS_BIGENDIAN
     value = bswap32(value);
 #endif
@@ -153,8 +164,10 @@ static uint32_t io_readl (void *opaque, target_phys_addr_t addr)
 #ifdef TARGET_WORDS_BIGENDIAN
     ret = bswap32(ret);
 #endif
+#if 0
     if (logfile)
         fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
+#endif
     return ret;
 }
 
@@ -181,9 +194,14 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
     int io_memory;
     int linux_boot;
     int ret;
+    CPUState *env;
 
     printf("%s: start\n", __func__);
     linux_boot = (kernel_filename != NULL);
+
+    env = cpu_init();
+    register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
+
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
     bios_offset = ram_size + vga_ram_size;
@@ -198,9 +216,9 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
                                  BIOS_SIZE, bios_offset | IO_MEM_ROM);
 #if 0
     memcpy(phys_ram_base + 0x10000, phys_ram_base + bios_offset, BIOS_SIZE);
-    cpu_single_env->PC = 0x80010004;
+    env->PC = 0x80010004;
 #else
-    cpu_single_env->PC = 0xBFC00004;
+    env->PC = 0xBFC00004;
 #endif
     if (linux_boot) {
         kernel_base = KERNEL_LOAD_ADDR;
@@ -226,7 +244,12 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
             initrd_base = 0;
             initrd_size = 0;
         }
-        cpu_single_env->PC = KERNEL_LOAD_ADDR;
+        env->PC = KERNEL_LOAD_ADDR;
+       /* Store command line.  */
+        strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline);
+        /* FIXME: little endian support */
+        *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
+        *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
     } else {
         kernel_base = 0;
         kernel_size = 0;
@@ -235,7 +258,7 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
     }
 
     /* Init internal devices */
-    cpu_mips_clock_init(cpu_single_env);
+    cpu_mips_clock_init(env);
     cpu_mips_irqctrl_init();
 
     /* Register 64 KB of ISA IO space at 0x14000000 */
@@ -243,13 +266,14 @@ void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
     cpu_register_physical_memory(0x14000000, 0x00010000, io_memory);
     isa_mem_base = 0x10000000;
 
-    isa_pic = pic_init(pic_irq_request, cpu_single_env);
+    isa_pic = pic_init(pic_irq_request, env);
     pit = pit_init(0x40, 0);
-    serial_init(0x3f8, 4, serial_hds[0]);
+    serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
     vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, 
                    vga_ram_size, 0, 0);
 
-    isa_ne2000_init(0x300, 9, &nd_table[0]);
+    if (nd_table[0].vlan)
+        isa_ne2000_init(0x300, 9, &nd_table[0]);
 }
 
 QEMUMachine mips_machine = {
index db61336..2940abd 100644 (file)
@@ -47,7 +47,9 @@
 #define EN0_CRDAHI     0x09    /* high byte, current remote dma address RD */
 #define EN0_RSARHI     0x09    /* Remote start address reg 1 */
 #define EN0_RCNTLO     0x0a    /* Remote byte count reg WR */
+#define EN0_RTL8029ID0 0x0a    /* Realtek ID byte #1 RD */
 #define EN0_RCNTHI     0x0b    /* Remote byte count reg WR */
+#define EN0_RTL8029ID1 0x0b    /* Realtek ID byte #2 RD */
 #define EN0_RSR                0x0c    /* rx status reg RD */
 #define EN0_RXCR       0x0c    /* RX configuration reg WR */
 #define EN0_TXCR       0x0d    /* TX configuration reg WR */
 #define EN2_STARTPG    0x21    /* Starting page of ring bfr RD */
 #define EN2_STOPPG     0x22    /* Ending page +1 of ring bfr RD */
 
+#define EN3_CONFIG0    0x33
+#define EN3_CONFIG1    0x34
+#define EN3_CONFIG2    0x35
+#define EN3_CONFIG3    0x36
+
 /*  Register accessed at EN_CMD, the 8390 base addr.  */
 #define E8390_STOP     0x01    /* Stop and reset the chip */
 #define E8390_START    0x02    /* Start the chip, clear reset */
@@ -122,6 +129,7 @@ typedef struct NE2000State {
     uint16_t rcnt;
     uint32_t rsar;
     uint8_t rsr;
+    uint8_t rxcr;
     uint8_t isr;
     uint8_t dcfg;
     uint8_t imr;
@@ -130,7 +138,8 @@ typedef struct NE2000State {
     uint8_t mult[8]; /* multicast mask array */
     int irq;
     PCIDevice *pci_dev;
-    NetDriverState *nd;
+    VLANClientState *vc;
+    uint8_t macaddr[6];
     uint8_t mem[NE2000_MEM_SIZE];
 } NE2000State;
 
@@ -139,7 +148,7 @@ static void ne2000_reset(NE2000State *s)
     int i;
 
     s->isr = ENISR_RESET;
-    memcpy(s->mem, s->nd->macaddr, 6);
+    memcpy(s->mem, s->macaddr, 6);
     s->mem[14] = 0x57;
     s->mem[15] = 0x57;
 
@@ -167,6 +176,30 @@ static void ne2000_update_irq(NE2000State *s)
     }
 }
 
+#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);
+}
+
 /* return the max buffer size if the NE2000 can receive more data */
 static int ne2000_can_receive(void *opaque)
 {
@@ -192,13 +225,46 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
 {
     NE2000State *s = opaque;
     uint8_t *p;
-    int total_len, next, avail, len, index;
+    int total_len, next, avail, len, index, mcast_idx;
     uint8_t buf1[60];
+    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 (!ne2000_can_receive(s))
+        return;
+    
+    /* XXX: check this */
+    if (s->rxcr & 0x10) {
+        /* promiscuous: receive all */
+    } else {
+        if (!memcmp(buf,  broadcast_macaddr, 6)) {
+            /* broadcast address */
+            if (!(s->rxcr & 0x04))
+                return;
+        } else if (buf[0] & 0x01) {
+            /* multicast */
+            if (!(s->rxcr & 0x08))
+                return;
+            mcast_idx = compute_mcast_idx(buf);
+            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[10] == buf[5]) {
+            /* match */
+        } else {
+            return;
+        }
+    }
+
+
     /* if too small buffer, then expand it */
     if (size < MIN_BUF_SIZE) {
         memcpy(buf1, buf, size);
@@ -273,7 +339,7 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
                     index -= NE2000_PMEM_SIZE;
                 /* fail safe: check range on the transmitted length  */
                 if (index + s->tcnt <= NE2000_PMEM_END) {
-                    qemu_send_packet(s->nd, s->mem + index, s->tcnt);
+                    qemu_send_packet(s->vc, s->mem + index, s->tcnt);
                 }
                 /* signal end of transfert */
                 s->tsr = ENTSR_PTX;
@@ -320,6 +386,9 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         case EN0_RCNTHI:
             s->rcnt = (s->rcnt & 0x00ff) | (val << 8);
             break;
+        case EN0_RXCR:
+            s->rxcr = val;
+            break;
         case EN0_DCFG:
             s->dcfg = val;
             break;
@@ -385,6 +454,21 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
         case EN2_STOPPG:
             ret = s->stop >> 8;
             break;
+       case EN0_RTL8029ID0:
+           ret = 0x50;
+           break;
+       case EN0_RTL8029ID1:
+           ret = 0x43;
+           break;
+       case EN3_CONFIG0:
+           ret = 0;            /* 10baseT media */
+           break;
+       case EN3_CONFIG2:
+           ret = 0x40;         /* 10baseT active */
+           break;
+       case EN3_CONFIG3:
+           ret = 0x40;         /* Full duplex */
+           break;
         default:
             ret = 0x00;
             break;
@@ -608,10 +692,10 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id)
        return 0;
 }
 
-void isa_ne2000_init(int base, int irq, NetDriverState *nd)
+void isa_ne2000_init(int base, int irq, NICInfo *nd)
 {
     NE2000State *s;
-
+    
     s = qemu_mallocz(sizeof(NE2000State));
     if (!s)
         return;
@@ -627,14 +711,22 @@ void isa_ne2000_init(int base, int irq, NetDriverState *nd)
     register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
     register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
     s->irq = irq;
-    s->nd = nd;
+    memcpy(s->macaddr, nd->macaddr, 6);
 
     ne2000_reset(s);
 
-    qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s);
-
+    s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, s);
+
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "ne2000 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]);
+             
     register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s);
-
 }
 
 /***********************************************************/
@@ -665,7 +757,7 @@ static void ne2000_map(PCIDevice *pci_dev, int region_num,
     register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
 }
 
-void pci_ne2000_init(PCIBus *bus, NetDriverState *nd)
+void pci_ne2000_init(PCIBus *bus, NICInfo *nd)
 {
     PCINE2000State *d;
     NE2000State *s;
@@ -690,10 +782,19 @@ void pci_ne2000_init(PCIBus *bus, NetDriverState *nd)
     s = &d->ne2000;
     s->irq = 16; // PCI interrupt
     s->pci_dev = (PCIDevice *)d;
-    s->nd = nd;
+    memcpy(s->macaddr, nd->macaddr, 6);
     ne2000_reset(s);
-    qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s);
-
+    s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, s);
+
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "ne2000 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]);
+             
     /* XXX: instance number ? */
     register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s);
     register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load, 
index 08fb9bd..3177337 100644 (file)
@@ -159,7 +159,7 @@ typedef struct IRQ_dst_t {
     uint32_t pcsr; /* CPU sensitivity register */
     IRQ_queue_t raised;
     IRQ_queue_t servicing;
-    CPUState *env; /* Needed if we did SMP */
+    CPUState *env;
 } IRQ_dst_t;
 
 struct openpic_t {
@@ -265,7 +265,7 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
     if (priority > dst->raised.priority) {
         IRQ_get_next(opp, &dst->raised);
         DPRINTF("Raise CPU IRQ\n");
-        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+        cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);
     }
 }
 
@@ -532,7 +532,7 @@ static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
         /* XXX: Should be able to reset any CPU */
         if (val & 1) {
             DPRINTF("Reset CPU IRQ\n");
-            //            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET);
+            //            cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET);
         }
        break;
 #if MAX_IPI > 0
@@ -781,7 +781,7 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
            src = &opp->src[n_IRQ];
            if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) {
                 DPRINTF("Raise CPU IRQ\n");
-                cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+                cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);
             }
        }
        break;
@@ -963,7 +963,8 @@ static void openpic_map(PCIDevice *pci_dev, int region_num,
 #endif
 }
 
-openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus)
+openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
+                         CPUPPCState **envp)
 {
     openpic_t *opp;
     uint8_t *pci_conf;
@@ -1017,6 +1018,8 @@ openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus)
     for (; i < MAX_IRQ; i++) {
         opp->src[i].type = IRQ_INTERNAL;
     }
+    for (i = 0; i < nb_cpus; i++)
+        opp->dst[i].env = envp[i];
     openpic_reset(opp);
     if (pmem_index)
         *pmem_index = opp->mem_index;
index a304d7f..cba9561 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * QEMU Parallel PORT emulation
  * 
- * Copyright (c) 2003-2004 Fabrice Bellard
+ * 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
@@ -50,6 +50,7 @@ struct ParallelState {
     int irq;
     int irq_pending;
     CharDriverState *chr;
+    int hw_driver;
 };
 
 static void parallel_update_irq(ParallelState *s)
@@ -70,29 +71,39 @@ static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 #endif
     switch(addr) {
     case 0:
-        s->data = val;
-        parallel_update_irq(s);
+        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);
+        }
         break;
     case 2:
-        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;
+        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;
+                    }
                 }
             }
+            parallel_update_irq(s);
+            s->control = val;
         }
-        parallel_update_irq(s);
-        s->control = val;
         break;
     }
 }
@@ -105,24 +116,35 @@ static uint32_t parallel_ioport_read(void *opaque, uint32_t addr)
     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; 
         break;
     case 1:
-        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 */
-                s->status |= PARA_STS_ACK;
-                s->status |= PARA_STS_BUSY;
+        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) {
+                /* 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;
+                }
             }
+            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);
+        }
         ret = s->control;
         break;
     }
@@ -132,39 +154,20 @@ static uint32_t parallel_ioport_read(void *opaque, uint32_t addr)
     return ret;
 }
 
-static int parallel_can_receive(ParallelState *s)
-{
-    return 0;
-}
-
-static void parallel_receive_byte(ParallelState *s, int ch)
-{
-}
-
-static int parallel_can_receive1(void *opaque)
-{
-    ParallelState *s = opaque;
-    return parallel_can_receive(s);
-}
-
-static void parallel_receive1(void *opaque, const uint8_t *buf, int size)
-{
-    ParallelState *s = opaque;
-    parallel_receive_byte(s, buf[0]);
-}
-
-static void parallel_event(void *opaque, int event)
-{
-}
-
 /* If fd is zero, it means that the parallel device uses the console */
 ParallelState *parallel_init(int base, int irq, CharDriverState *chr)
 {
     ParallelState *s;
+    uint8_t dummy;
 
     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)
+        s->hw_driver = 1;
+
     s->irq = irq;
     s->data = 0;
     s->status = PARA_STS_BUSY;
@@ -176,8 +179,5 @@ ParallelState *parallel_init(int base, int irq, CharDriverState *chr)
 
     register_ioport_write(base, 8, 1, parallel_ioport_write, s);
     register_ioport_read(base, 8, 1, parallel_ioport_read, s);
-    s->chr = chr;
-    qemu_chr_add_read_handler(chr, parallel_can_receive1, parallel_receive1, s);
-    qemu_chr_add_event_handler(chr, parallel_event);
     return s;
 }
index f0ae1b9..8e750b6 100644 (file)
@@ -42,6 +42,7 @@ static fdctrl_t *floppy_controller;
 static RTCState *rtc_state;
 static PITState *pit;
 static IOAPICState *ioapic;
+static USBPort *usb_root_ports[2];
 
 static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
 {
@@ -85,10 +86,11 @@ int cpu_get_pic_interrupt(CPUState *env)
 
 static void pic_irq_request(void *opaque, int level)
 {
+    CPUState *env = opaque;
     if (level)
-        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
     else
-        cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
 }
 
 /* PC cmos mappings */
@@ -286,15 +288,26 @@ static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
       (dummy_refresh_clock << 4);
 }
 
+void ioport_set_a20(int enable)
+{
+    /* XXX: send to all CPUs ? */
+    cpu_x86_set_a20(first_cpu, enable);
+}
+
+int ioport_get_a20(void)
+{
+    return ((first_cpu->a20_mask >> 20) & 1);
+}
+
 static void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
 {
-    cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1);
+    ioport_set_a20((val >> 1) & 1);
     /* XXX: bit 0 is fast reset */
 }
 
 static uint32_t ioport92_read(void *opaque, uint32_t addr)
 {
-    return ((cpu_single_env->a20_mask >> 20) & 1) << 1;
+    return ioport_get_a20() << 1;
 }
 
 /***********************************************************/
@@ -390,6 +403,162 @@ int load_kernel(const char *filename, uint8_t *addr,
     return -1;
 }
 
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    cpu_reset(env);
+}
+
+/*************************************************/
+
+static void putb(uint8_t **pp, int val)
+{
+    uint8_t *q;
+    q = *pp;
+    *q++ = val;
+    *pp = q;
+}
+
+static void putstr(uint8_t **pp, const char *str)
+{
+    uint8_t *q;
+    q = *pp;
+    while (*str)
+        *q++ = *str++;
+    *pp = q;
+}
+
+static void putle16(uint8_t **pp, int val)
+{
+    uint8_t *q;
+    q = *pp;
+    *q++ = val;
+    *q++ = val >> 8;
+    *pp = q;
+}
+
+static void putle32(uint8_t **pp, int val)
+{
+    uint8_t *q;
+    q = *pp;
+    *q++ = val;
+    *q++ = val >> 8;
+    *q++ = val >> 16;
+    *q++ = val >> 24;
+    *pp = q;
+}
+
+static int mpf_checksum(const uint8_t *data, int len)
+{
+    int sum, i;
+    sum = 0;
+    for(i = 0; i < len; i++)
+        sum += data[i];
+    return sum & 0xff;
+}
+
+/* Build the Multi Processor table in the BIOS. Same values as Bochs. */
+static void bios_add_mptable(uint8_t *bios_data)
+{
+    uint8_t *mp_config_table, *q, *float_pointer_struct;
+    int ioapic_id, offset, i, len;
+    
+    if (smp_cpus <= 1)
+        return;
+
+    mp_config_table = bios_data + 0xb000;
+    q = mp_config_table;
+    putstr(&q, "PCMP"); /* "PCMP signature */
+    putle16(&q, 0); /* table length (patched later) */
+    putb(&q, 4); /* spec rev */
+    putb(&q, 0); /* checksum (patched later) */
+    putstr(&q, "QEMUCPU "); /* OEM id */
+    putstr(&q, "0.1         "); /* vendor id */
+    putle32(&q, 0); /* OEM table ptr */
+    putle16(&q, 0); /* OEM table size */
+    putle16(&q, 20); /* entry count */
+    putle32(&q, 0xfee00000); /* local APIC addr */
+    putle16(&q, 0); /* ext table length */
+    putb(&q, 0); /* ext table checksum */
+    putb(&q, 0); /* reserved */
+    
+    for(i = 0; i < smp_cpus; i++) {
+        putb(&q, 0); /* entry type = processor */
+        putb(&q, i); /* APIC id */
+        putb(&q, 0x11); /* local APIC version number */
+        if (i == 0)
+            putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */
+        else
+            putb(&q, 1); /* cpu flags: enabled */
+        putb(&q, 0); /* cpu signature */
+        putb(&q, 6);
+        putb(&q, 0);
+        putb(&q, 0);
+        putle16(&q, 0x201); /* feature flags */
+        putle16(&q, 0);
+
+        putle16(&q, 0); /* reserved */
+        putle16(&q, 0);
+        putle16(&q, 0);
+        putle16(&q, 0);
+    }
+
+    /* isa bus */
+    putb(&q, 1); /* entry type = bus */
+    putb(&q, 0); /* bus ID */
+    putstr(&q, "ISA   ");
+    
+    /* ioapic */
+    ioapic_id = smp_cpus;
+    putb(&q, 2); /* entry type = I/O APIC */
+    putb(&q, ioapic_id); /* apic ID */
+    putb(&q, 0x11); /* I/O APIC version number */
+    putb(&q, 1); /* enable */
+    putle32(&q, 0xfec00000); /* I/O APIC addr */
+
+    /* irqs */
+    for(i = 0; i < 16; i++) {
+        putb(&q, 3); /* entry type = I/O interrupt */
+        putb(&q, 0); /* interrupt type = vectored interrupt */
+        putb(&q, 0); /* flags: po=0, el=0 */
+        putb(&q, 0);
+        putb(&q, 0); /* source bus ID = ISA */
+        putb(&q, i); /* source bus IRQ */
+        putb(&q, ioapic_id); /* dest I/O APIC ID */
+        putb(&q, i); /* dest I/O APIC interrupt in */
+    }
+    /* patch length */
+    len = q - mp_config_table;
+    mp_config_table[4] = len;
+    mp_config_table[5] = len >> 8;
+
+    mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table);
+
+    /* align to 16 */
+    offset = q - bios_data;
+    offset = (offset + 15) & ~15;
+    float_pointer_struct = bios_data + offset;
+    
+    /* floating pointer structure */
+    q = float_pointer_struct;
+    putstr(&q, "_MP_");
+    /* pointer to MP config table */
+    putle32(&q, mp_config_table - bios_data + 0x000f0000); 
+
+    putb(&q, 1); /* length in 16 byte units */
+    putb(&q, 4); /* MP spec revision */
+    putb(&q, 0); /* checksum (patched later) */
+    putb(&q, 0); /* MP feature byte 1 */
+
+    putb(&q, 0);
+    putb(&q, 0);
+    putb(&q, 0);
+    putb(&q, 0);
+    float_pointer_struct[10] = 
+        -mpf_checksum(float_pointer_struct, q - float_pointer_struct);
+}
+
+
 static const int ide_iobase[2] = { 0x1f0, 0x170 };
 static const int ide_iobase2[2] = { 0x3f6, 0x376 };
 static const int ide_irq[2] = { 14, 15 };
@@ -405,20 +574,70 @@ static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
 static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
 static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
 
+#ifdef HAS_AUDIO
+static void audio_init (PCIBus *pci_bus)
+{
+    struct soundhw *c;
+    int audio_enabled = 0;
+
+    for (c = soundhw; !audio_enabled && c->name; ++c) {
+        audio_enabled = c->enabled;
+    }
+
+    if (audio_enabled) {
+        AudioState *s;
+
+        s = AUD_init ();
+        if (s) {
+            for (c = soundhw; c->name; ++c) {
+                if (c->enabled) {
+                    if (c->isa) {
+                        c->init.init_isa (s);
+                    }
+                    else {
+                        if (pci_bus) {
+                            c->init.init_pci (pci_bus, s);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+#endif
+
 /* PC hardware initialisation */
 static void pc_init1(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,
+                     int pci_enabled)
 {
     char buf[1024];
     int ret, linux_boot, initrd_size, i, nb_nics1;
     unsigned long bios_offset, vga_bios_offset;
     int bios_size, isa_bios_size;
     PCIBus *pci_bus;
+    CPUState *env;
 
     linux_boot = (kernel_filename != NULL);
 
+    /* init CPUs */
+    for(i = 0; i < smp_cpus; i++) {
+        env = cpu_init();
+        if (i != 0)
+            env->hflags |= HF_HALTED_MASK;
+        if (smp_cpus > 1) {
+            /* XXX: enable it in all cases */
+            env->cpuid_features |= CPUID_APIC;
+        }
+        register_savevm("cpu", i, 3, cpu_save, cpu_load, env);
+        qemu_register_reset(main_cpu_reset, env);
+        if (pci_enabled) {
+            apic_init(env);
+        }
+    }
+
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, 0);
 
@@ -439,6 +658,9 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
         fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf);
         exit(1);
     }
+    if (bios_size == 65536) {
+        bios_add_mptable(phys_ram_base + bios_offset);
+    }
 
     /* VGA BIOS load */
     if (cirrus_vga_enabled) {
@@ -557,10 +779,9 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
     register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
 
     if (pci_enabled) {
-        apic_init(cpu_single_env);
         ioapic = ioapic_init();
     }
-    isa_pic = pic_init(pic_irq_request, cpu_single_env);
+    isa_pic = pic_init(pic_irq_request, first_cpu);
     pit = pit_init(0x40, 0);
     if (pci_enabled) {
         pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
@@ -568,7 +789,8 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
-            serial_init(serial_io[i], serial_irq[i], serial_hds[i]);
+            serial_init(&pic_set_irq_new, isa_pic,
+                        serial_io[i], serial_irq[i], serial_hds[i]);
         }
     }
 
@@ -599,27 +821,19 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
 
     kbd_init();
     DMA_init(0);
-
-    if (audio_enabled) {
-        AUD_init();
-#ifdef USE_SB16
-        if (sb16_enabled)
-            SB16_init ();
-#endif
-#ifdef CONFIG_ADLIB
-        if (adlib_enabled)
-            Adlib_init ();
+#ifdef HAS_AUDIO
+    audio_init(pci_enabled ? pci_bus : NULL);
 #endif
-#ifdef USE_GUS
-        if (gus_enabled)
-            GUS_init ();
-#endif
-    }
 
     floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
 
     cmos_init(ram_size, boot_device, bs_table);
 
+    if (pci_enabled && usb_enabled) {
+        usb_uhci_init(pci_bus, usb_root_ports);
+        usb_attach(usb_root_ports[0], vm_usb_hub);
+    }
+
     /* must be done after all PCI devices are instanciated */
     /* XXX: should be done in the Bochs BIOS */
     if (pci_enabled) {
@@ -627,8 +841,40 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
     }
 }
 
+static void pc_init_pci(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)
+{
+    pc_init1(ram_size, vga_ram_size, boot_device,
+             ds, fd_filename, snapshot,
+             kernel_filename, kernel_cmdline,
+             initrd_filename, 1);
+}
+
+static void pc_init_isa(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)
+{
+    pc_init1(ram_size, vga_ram_size, boot_device,
+             ds, fd_filename, snapshot,
+             kernel_filename, kernel_cmdline,
+             initrd_filename, 0);
+}
+
 QEMUMachine pc_machine = {
     "pc",
     "Standard PC",
-    pc_init1,
+    pc_init_pci,
+};
+
+QEMUMachine isapc_machine = {
+    "isapc",
+    "ISA-only PC",
+    pc_init_isa,
 };
index efca2cd..f3456ba 100644 (file)
@@ -1616,32 +1616,32 @@ void pci_info(void)
 
 static __attribute__((unused)) uint32_t isa_inb(uint32_t addr)
 {
-    return cpu_inb(cpu_single_env, addr);
+    return cpu_inb(NULL, addr);
 }
 
 static void isa_outb(uint32_t val, uint32_t addr)
 {
-    cpu_outb(cpu_single_env, addr, val);
+    cpu_outb(NULL, addr, val);
 }
 
 static __attribute__((unused)) uint32_t isa_inw(uint32_t addr)
 {
-    return cpu_inw(cpu_single_env, addr);
+    return cpu_inw(NULL, addr);
 }
 
 static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr)
 {
-    cpu_outw(cpu_single_env, addr, val);
+    cpu_outw(NULL, addr, val);
 }
 
 static __attribute__((unused)) uint32_t isa_inl(uint32_t addr)
 {
-    return cpu_inl(cpu_single_env, addr);
+    return cpu_inl(NULL, addr);
 }
 
 static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr)
 {
-    cpu_outl(cpu_single_env, addr, val);
+    cpu_outl(NULL, addr, val);
 }
 
 static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
index be559eb..61f8a63 100644 (file)
 
 #define KBD_QUEUE_SIZE 256
 
-typedef struct {
-    uint8_t aux[KBD_QUEUE_SIZE];
-    uint8_t data[KBD_QUEUE_SIZE];
-    int rptr, wptr, count;
-} KBDQueue;
+#define KBD_PENDING_KBD         1
+#define KBD_PENDING_AUX         2
 
 typedef struct KBDState {
-    KBDQueue queue;
     uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
     uint8_t status;
     uint8_t mode;
-    /* keyboard state */
-    int kbd_write_cmd;
-    int scan_enabled;
-    /* mouse state */
-    int mouse_write_cmd;
-    uint8_t mouse_status;
-    uint8_t mouse_resolution;
-    uint8_t mouse_sample_rate;
-    uint8_t mouse_wrap;
-    uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
-    uint8_t mouse_detect_state;
-    int mouse_dx; /* current values, needed for 'poll' mode */
-    int mouse_dy;
-    int mouse_dz;
-    uint8_t mouse_buttons;
+    /* Bitmask of devices with data available.  */
+    int pending;
+    void *kbd;
+    void *mouse;
 } KBDState;
 
 KBDState kbd_state;
@@ -145,15 +130,15 @@ KBDState kbd_state;
    incorrect, but it avoids having to simulate exact delays */
 static void kbd_update_irq(KBDState *s)
 {
-    KBDQueue *q = &s->queue;
     int irq12_level, irq1_level;
 
     irq1_level = 0;    
     irq12_level = 0;    
     s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
-    if (q->count != 0) {
+    if (s->pending) {
         s->status |= KBD_STAT_OBF;
-        if (q->aux[q->rptr]) {
+        /* kdb 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;
@@ -167,32 +152,26 @@ static void kbd_update_irq(KBDState *s)
     pic_set_irq(12, irq12_level);
 }
 
-static void kbd_queue(KBDState *s, int b, int aux)
+static void kbd_update_kbd_irq(void *opaque, int level)
 {
-    KBDQueue *q = &s->queue;
+    KBDState *s = (KBDState *)opaque;
 
-#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
-    if (aux)
-        printf("mouse event: 0x%02x\n", b);
-#ifdef DEBUG_KBD
+    if (level)
+        s->pending |= KBD_PENDING_KBD;
     else
-        printf("kbd event: 0x%02x\n", b);
-#endif
-#endif
-    if (q->count >= KBD_QUEUE_SIZE)
-        return;
-    q->aux[q->wptr] = aux;
-    q->data[q->wptr] = b;
-    if (++q->wptr == KBD_QUEUE_SIZE)
-        q->wptr = 0;
-    q->count++;
+        s->pending &= ~KBD_PENDING_KBD;
     kbd_update_irq(s);
 }
 
-static void pc_kbd_put_keycode(void *opaque, int keycode)
+static void kbd_update_aux_irq(void *opaque, int level)
 {
-    KBDState *s = opaque;
-    kbd_queue(s, keycode, 0);
+    KBDState *s = (KBDState *)opaque;
+
+    if (level)
+        s->pending |= KBD_PENDING_AUX;
+    else
+        s->pending &= ~KBD_PENDING_AUX;
+    kbd_update_irq(s);
 }
 
 static uint32_t kbd_read_status(void *opaque, uint32_t addr)
@@ -206,6 +185,14 @@ static uint32_t kbd_read_status(void *opaque, uint32_t addr)
     return val;
 }
 
+static void kbd_queue(KBDState *s, int b, int aux)
+{
+    if (aux)
+        ps2_queue(s->mouse, b);
+    else
+        ps2_queue(s->kbd, b);
+}
+
 static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
 {
     KBDState *s = opaque;
@@ -254,7 +241,7 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
     case KBD_CCMD_READ_OUTPORT:
         /* XXX: check that */
 #ifdef TARGET_I386
-        val = 0x01 | (((cpu_single_env->a20_mask >> 20) & 1) << 1);
+        val = 0x01 | (ioport_get_a20() << 1);
 #else
         val = 0x01;
 #endif
@@ -266,10 +253,10 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
         break;
 #ifdef TARGET_I386
     case KBD_CCMD_ENABLE_A20:
-        cpu_x86_set_a20(cpu_single_env, 1);
+        ioport_set_a20(1);
         break;
     case KBD_CCMD_DISABLE_A20:
-        cpu_x86_set_a20(cpu_single_env, 0);
+        ioport_set_a20(0);
         break;
 #endif
     case KBD_CCMD_RESET:
@@ -287,304 +274,11 @@ static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
 static uint32_t kbd_read_data(void *opaque, uint32_t addr)
 {
     KBDState *s = opaque;
-    KBDQueue *q;
-    int val, index, aux;
-    
-    q = &s->queue;
-    if (q->count == 0) {
-        /* NOTE: if no data left, we return the last keyboard one
-           (needed for EMM386) */
-        /* XXX: need a timer to do things correctly */
-        index = q->rptr - 1;
-        if (index < 0)
-            index = KBD_QUEUE_SIZE - 1;
-        val = q->data[index];
-    } else {
-        aux = q->aux[q->rptr];
-        val = q->data[q->rptr];
-        if (++q->rptr == KBD_QUEUE_SIZE)
-            q->rptr = 0;
-        q->count--;
-        /* reading deasserts IRQ */
-        if (aux)
-            pic_set_irq(12, 0);
-        else
-            pic_set_irq(1, 0);
-    }
-    /* reassert IRQs if data left */
-    kbd_update_irq(s);
-#ifdef DEBUG_KBD
-    printf("kbd: read data=0x%02x\n", val);
-#endif
-    return val;
-}
-
-static void kbd_reset_keyboard(KBDState *s)
-{
-    s->scan_enabled = 1;
-}
-
-static void kbd_write_keyboard(KBDState *s, int val)
-{
-    switch(s->kbd_write_cmd) {
-    default:
-    case -1:
-        switch(val) {
-        case 0x00:
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            break;
-        case 0x05:
-            kbd_queue(s, KBD_REPLY_RESEND, 0);
-            break;
-        case KBD_CMD_GET_ID:
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            kbd_queue(s, 0xab, 0);
-            kbd_queue(s, 0x83, 0);
-            break;
-        case KBD_CMD_ECHO:
-            kbd_queue(s, KBD_CMD_ECHO, 0);
-            break;
-        case KBD_CMD_ENABLE:
-            s->scan_enabled = 1;
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            break;
-        case KBD_CMD_SET_LEDS:
-        case KBD_CMD_SET_RATE:
-            s->kbd_write_cmd = val;
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            break;
-        case KBD_CMD_RESET_DISABLE:
-            kbd_reset_keyboard(s);
-            s->scan_enabled = 0;
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            break;
-        case KBD_CMD_RESET_ENABLE:
-            kbd_reset_keyboard(s);
-            s->scan_enabled = 1;
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            break;
-        case KBD_CMD_RESET:
-            kbd_reset_keyboard(s);
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            kbd_queue(s, KBD_REPLY_POR, 0);
-            break;
-        default:
-            kbd_queue(s, KBD_REPLY_ACK, 0);
-            break;
-        }
-        break;
-    case KBD_CMD_SET_LEDS:
-        kbd_queue(s, KBD_REPLY_ACK, 0);
-        s->kbd_write_cmd = -1;
-        break;
-    case KBD_CMD_SET_RATE:
-        kbd_queue(s, KBD_REPLY_ACK, 0);
-        s->kbd_write_cmd = -1;
-        break;
-    }
-}
-
-static void kbd_mouse_send_packet(KBDState *s)
-{
-    unsigned int b;
-    int dx1, dy1, dz1;
-
-    dx1 = s->mouse_dx;
-    dy1 = s->mouse_dy;
-    dz1 = s->mouse_dz;
-    /* XXX: increase range to 8 bits ? */
-    if (dx1 > 127)
-        dx1 = 127;
-    else if (dx1 < -127)
-        dx1 = -127;
-    if (dy1 > 127)
-        dy1 = 127;
-    else if (dy1 < -127)
-        dy1 = -127;
-    b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
-    kbd_queue(s, b, 1);
-    kbd_queue(s, dx1 & 0xff, 1);
-    kbd_queue(s, dy1 & 0xff, 1);
-    /* extra byte for IMPS/2 or IMEX */
-    switch(s->mouse_type) {
-    default:
-        break;
-    case 3:
-        if (dz1 > 127)
-            dz1 = 127;
-        else if (dz1 < -127)
-                dz1 = -127;
-        kbd_queue(s, dz1 & 0xff, 1);
-        break;
-    case 4:
-        if (dz1 > 7)
-            dz1 = 7;
-        else if (dz1 < -7)
-            dz1 = -7;
-        b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
-        kbd_queue(s, b, 1);
-        break;
-    }
-
-    /* update deltas */
-    s->mouse_dx -= dx1;
-    s->mouse_dy -= dy1;
-    s->mouse_dz -= dz1;
-}
-
-static void pc_kbd_mouse_event(void *opaque, 
-                               int dx, int dy, int dz, int buttons_state)
-{
-    KBDState *s = opaque;
 
-    /* check if deltas are recorded when disabled */
-    if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
-        return;
-
-    s->mouse_dx += dx;
-    s->mouse_dy -= dy;
-    s->mouse_dz += dz;
-    /* XXX: SDL sometimes generates nul events: we delete them */
-    if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
-        s->mouse_buttons == buttons_state)
-       return;
-    s->mouse_buttons = buttons_state;
-    
-    if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
-        (s->queue.count < (KBD_QUEUE_SIZE - 16))) {
-        for(;;) {
-            /* if not remote, send event. Multiple events are sent if
-               too big deltas */
-            kbd_mouse_send_packet(s);
-            if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
-                break;
-        }
-    }
-}
+    if (s->pending == KBD_PENDING_AUX)
+        return ps2_read_data(s->mouse);
 
-static void kbd_write_mouse(KBDState *s, int val)
-{
-#ifdef DEBUG_MOUSE
-    printf("kbd: write mouse 0x%02x\n", val);
-#endif
-    switch(s->mouse_write_cmd) {
-    default:
-    case -1:
-        /* mouse command */
-        if (s->mouse_wrap) {
-            if (val == AUX_RESET_WRAP) {
-                s->mouse_wrap = 0;
-                kbd_queue(s, AUX_ACK, 1);
-                return;
-            } else if (val != AUX_RESET) {
-                kbd_queue(s, val, 1);
-                return;
-            }
-        }
-        switch(val) {
-        case AUX_SET_SCALE11:
-            s->mouse_status &= ~MOUSE_STATUS_SCALE21;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_SET_SCALE21:
-            s->mouse_status |= MOUSE_STATUS_SCALE21;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_SET_STREAM:
-            s->mouse_status &= ~MOUSE_STATUS_REMOTE;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_SET_WRAP:
-            s->mouse_wrap = 1;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_SET_REMOTE:
-            s->mouse_status |= MOUSE_STATUS_REMOTE;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_GET_TYPE:
-            kbd_queue(s, AUX_ACK, 1);
-            kbd_queue(s, s->mouse_type, 1);
-            break;
-        case AUX_SET_RES:
-        case AUX_SET_SAMPLE:
-            s->mouse_write_cmd = val;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_GET_SCALE:
-            kbd_queue(s, AUX_ACK, 1);
-            kbd_queue(s, s->mouse_status, 1);
-            kbd_queue(s, s->mouse_resolution, 1);
-            kbd_queue(s, s->mouse_sample_rate, 1);
-            break;
-        case AUX_POLL:
-            kbd_queue(s, AUX_ACK, 1);
-            kbd_mouse_send_packet(s);
-            break;
-        case AUX_ENABLE_DEV:
-            s->mouse_status |= MOUSE_STATUS_ENABLED;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_DISABLE_DEV:
-            s->mouse_status &= ~MOUSE_STATUS_ENABLED;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_SET_DEFAULT:
-            s->mouse_sample_rate = 100;
-            s->mouse_resolution = 2;
-            s->mouse_status = 0;
-            kbd_queue(s, AUX_ACK, 1);
-            break;
-        case AUX_RESET:
-            s->mouse_sample_rate = 100;
-            s->mouse_resolution = 2;
-            s->mouse_status = 0;
-            s->mouse_type = 0;
-            kbd_queue(s, AUX_ACK, 1);
-            kbd_queue(s, 0xaa, 1);
-            kbd_queue(s, s->mouse_type, 1);
-            break;
-        default:
-            break;
-        }
-        break;
-    case AUX_SET_SAMPLE:
-        s->mouse_sample_rate = val;
-        /* detect IMPS/2 or IMEX */
-        switch(s->mouse_detect_state) {
-        default:
-        case 0:
-            if (val == 200)
-                s->mouse_detect_state = 1;
-            break;
-        case 1:
-            if (val == 100)
-                s->mouse_detect_state = 2;
-            else if (val == 200)
-                s->mouse_detect_state = 3;
-            else
-                s->mouse_detect_state = 0;
-            break;
-        case 2:
-            if (val == 80) 
-                s->mouse_type = 3; /* IMPS/2 */
-            s->mouse_detect_state = 0;
-            break;
-        case 3:
-            if (val == 80) 
-                s->mouse_type = 4; /* IMEX */
-            s->mouse_detect_state = 0;
-            break;
-        }
-        kbd_queue(s, AUX_ACK, 1);
-        s->mouse_write_cmd = -1;
-        break;
-    case AUX_SET_RES:
-        s->mouse_resolution = val;
-        kbd_queue(s, AUX_ACK, 1);
-        s->mouse_write_cmd = -1;
-        break;
-    }
+    return ps2_read_data(s->kbd);
 }
 
 void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
@@ -597,10 +291,11 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
 
     switch(s->write_cmd) {
     case 0:
-        kbd_write_keyboard(s, val);
+        ps2_write_keyboard(s->kbd, val);
         break;
     case KBD_CCMD_WRITE_MODE:
         s->mode = val;
+        /* ??? */
         kbd_update_irq(s);
         break;
     case KBD_CCMD_WRITE_OBUF:
@@ -611,14 +306,14 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
         break;
     case KBD_CCMD_WRITE_OUTPORT:
 #ifdef TARGET_I386
-        cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1);
+        ioport_set_a20((val >> 1) & 1);
 #endif
         if (!(val & 1)) {
             qemu_system_reset_request();
         }
         break;
     case KBD_CCMD_WRITE_MOUSE:
-        kbd_write_mouse(s, val);
+        ps2_write_mouse(s->mouse, val);
         break;
     default:
         break;
@@ -629,16 +324,9 @@ void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
 static void kbd_reset(void *opaque)
 {
     KBDState *s = opaque;
-    KBDQueue *q;
 
-    s->kbd_write_cmd = -1;
-    s->mouse_write_cmd = -1;
     s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
     s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
-    q = &s->queue;
-    q->rptr = 0;
-    q->wptr = 0;
-    q->count = 0;
 }
 
 static void kbd_save(QEMUFile* f, void* opaque)
@@ -648,43 +336,17 @@ static void kbd_save(QEMUFile* f, void* opaque)
     qemu_put_8s(f, &s->write_cmd);
     qemu_put_8s(f, &s->status);
     qemu_put_8s(f, &s->mode);
-    qemu_put_be32s(f, &s->kbd_write_cmd);
-    qemu_put_be32s(f, &s->scan_enabled);
-    qemu_put_be32s(f, &s->mouse_write_cmd);
-    qemu_put_8s(f, &s->mouse_status);
-    qemu_put_8s(f, &s->mouse_resolution);
-    qemu_put_8s(f, &s->mouse_sample_rate);
-    qemu_put_8s(f, &s->mouse_wrap);
-    qemu_put_8s(f, &s->mouse_type);
-    qemu_put_8s(f, &s->mouse_detect_state);
-    qemu_put_be32s(f, &s->mouse_dx);
-    qemu_put_be32s(f, &s->mouse_dy);
-    qemu_put_be32s(f, &s->mouse_dz);
-    qemu_put_8s(f, &s->mouse_buttons);
 }
 
 static int kbd_load(QEMUFile* f, void* opaque, int version_id)
 {
     KBDState *s = (KBDState*)opaque;
     
-    if (version_id != 1)
+    if (version_id != 2)
         return -EINVAL;
     qemu_get_8s(f, &s->write_cmd);
     qemu_get_8s(f, &s->status);
     qemu_get_8s(f, &s->mode);
-    qemu_get_be32s(f, &s->kbd_write_cmd);
-    qemu_get_be32s(f, &s->scan_enabled);
-    qemu_get_be32s(f, &s->mouse_write_cmd);
-    qemu_get_8s(f, &s->mouse_status);
-    qemu_get_8s(f, &s->mouse_resolution);
-    qemu_get_8s(f, &s->mouse_sample_rate);
-    qemu_get_8s(f, &s->mouse_wrap);
-    qemu_get_8s(f, &s->mouse_type);
-    qemu_get_8s(f, &s->mouse_detect_state);
-    qemu_get_be32s(f, &s->mouse_dx);
-    qemu_get_be32s(f, &s->mouse_dy);
-    qemu_get_be32s(f, &s->mouse_dz);
-    qemu_get_8s(f, &s->mouse_buttons);
     return 0;
 }
 
@@ -693,13 +355,13 @@ void kbd_init(void)
     KBDState *s = &kbd_state;
     
     kbd_reset(s);
-    register_savevm("pckbd", 0, 1, kbd_save, kbd_load, s);
+    register_savevm("pckbd", 0, 2, 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);
 
-    qemu_add_kbd_event_handler(pc_kbd_put_keycode, s);
-    qemu_add_mouse_event_handler(pc_kbd_mouse_event, s);
+    s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
+    s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
     qemu_register_reset(kbd_reset, s);
 }
index c460fec..3743ad7 100644 (file)
@@ -283,61 +283,45 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
 /* NVRAM helpers */
 void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
 {
-    m48t59_set_addr(nvram, addr);
-    m48t59_write(nvram, value);
+    m48t59_write(nvram, addr, value);
 }
 
 uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
 {
-    m48t59_set_addr(nvram, addr);
-    return m48t59_read(nvram);
+    return m48t59_read(nvram, addr);
 }
 
 void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
 {
-    m48t59_set_addr(nvram, addr);
-    m48t59_write(nvram, value >> 8);
-    m48t59_set_addr(nvram, addr + 1);
-    m48t59_write(nvram, value & 0xFF);
+    m48t59_write(nvram, addr, value >> 8);
+    m48t59_write(nvram, addr + 1, value & 0xFF);
 }
 
 uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
 {
     uint16_t tmp;
 
-    m48t59_set_addr(nvram, addr);
-    tmp = m48t59_read(nvram) << 8;
-    m48t59_set_addr(nvram, addr + 1);
-    tmp |= m48t59_read(nvram);
-
+    tmp = m48t59_read(nvram, addr) << 8;
+    tmp |= m48t59_read(nvram, addr + 1);
     return tmp;
 }
 
 void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
 {
-    m48t59_set_addr(nvram, addr);
-    m48t59_write(nvram, value >> 24);
-    m48t59_set_addr(nvram, addr + 1);
-    m48t59_write(nvram, (value >> 16) & 0xFF);
-    m48t59_set_addr(nvram, addr + 2);
-    m48t59_write(nvram, (value >> 8) & 0xFF);
-    m48t59_set_addr(nvram, addr + 3);
-    m48t59_write(nvram, value & 0xFF);
+    m48t59_write(nvram, addr, value >> 24);
+    m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF);
+    m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF);
+    m48t59_write(nvram, addr + 3, value & 0xFF);
 }
 
 uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
 {
     uint32_t tmp;
 
-    m48t59_set_addr(nvram, addr);
-    tmp = m48t59_read(nvram) << 24;
-    m48t59_set_addr(nvram, addr + 1);
-    tmp |= m48t59_read(nvram) << 16;
-    m48t59_set_addr(nvram, addr + 2);
-    tmp |= m48t59_read(nvram) << 8;
-    m48t59_set_addr(nvram, addr + 3);
-    tmp |= m48t59_read(nvram);
-
+    tmp = m48t59_read(nvram, addr) << 24;
+    tmp |= m48t59_read(nvram, addr + 1) << 16;
+    tmp |= m48t59_read(nvram, addr + 2) << 8;
+    tmp |= m48t59_read(nvram, addr + 3);
     return tmp;
 }
 
@@ -347,11 +331,9 @@ void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
     int i;
 
     for (i = 0; i < max && str[i] != '\0'; i++) {
-        m48t59_set_addr(nvram, addr + i);
-        m48t59_write(nvram, str[i]);
+        m48t59_write(nvram, addr + i, str[i]);
     }
-    m48t59_set_addr(nvram, addr + max - 1);
-    m48t59_write(nvram, '\0');
+    m48t59_write(nvram, addr + max - 1, '\0');
 }
 
 int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
index a76fc47..5187372 100644 (file)
@@ -300,6 +300,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
                           const char *initrd_filename,
                           int is_heathrow)
 {
+    CPUState *env;
     char buf[1024];
     SetIRQFunc *set_irq;
     void *pic;
@@ -315,6 +316,36 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
 
     linux_boot = (kernel_filename != NULL);
 
+    /* init CPUs */
+    env = cpu_init();
+    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 (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;
+
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
 
@@ -381,31 +412,6 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
         initrd_base = 0;
         initrd_size = 0;
     }
-    /* 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 (def == NULL) {
-        cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n");
-    }
-    cpu_ppc_register(cpu_single_env, def);
-
-    /* Set time-base frequency to 100 Mhz */
-    cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);
-
-    cpu_single_env->osi_call = vga_osi_call;
 
     if (is_heathrow) {
         isa_mem_base = 0x80000000;
@@ -427,7 +433,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
         isa_pic = pic_init(pic_irq_request, NULL);
         
         /* XXX: use Mac Serial port */
-        serial_init(0x3f8, 4, serial_hds[0]);
+        serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
         
         for(i = 0; i < nb_nics; i++) {
             pci_ne2000_init(pci_bus, &nd_table[i]);
@@ -449,7 +455,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
 
         macio_init(pci_bus, 0x0017);
         
-        nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE);
+        nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
         
         arch_name = "HEATHROW";
     } else {
@@ -468,7 +474,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
         vga_initialize(pci_bus, ds, phys_ram_base + ram_size,
                        ram_size, vga_ram_size,
                        vga_bios_offset, vga_bios_size);
-        pic = openpic_init(NULL, &openpic_mem_index, 1);
+        pic = openpic_init(NULL, &openpic_mem_index, 1, &env);
         set_irq = openpic_set_irq;
         pci_set_pic(pci_bus, set_irq, pic);
 
@@ -476,7 +482,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
         isa_pic = pic_init(pic_irq_request, NULL);
         
         /* XXX: use Mac Serial port */
-        serial_init(0x3f8, 4, serial_hds[0]);
+        serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
         
         for(i = 0; i < nb_nics; i++) {
             pci_ne2000_init(pci_bus, &nd_table[i]);
@@ -496,7 +502,7 @@ static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
         
         macio_init(pci_bus, 0x0022);
         
-        nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE);
+        nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
         
         arch_name = "MAC99";
     }
index 148a08a..d4f3021 100644 (file)
@@ -99,9 +99,9 @@ static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
 static void pic_irq_request(void *opaque, int level)
 {
     if (level)
-        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+        cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD);
     else
-        cpu_reset_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+        cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD);
 }
 
 /* PCI intack register */
@@ -294,7 +294,7 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
         /* Special port 92 */
         /* Check soft reset asked */
         if (val & 0x01) {
-            //            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET);
+            //            cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET);
         }
         /* Check LE mode */
         if (val & 0x02) {
@@ -331,7 +331,7 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
         break;
     case 0x0814:
         /* L2 invalidate register */
-        //        tlb_flush(cpu_single_env, 1);
+        //        tlb_flush(first_cpu, 1);
         break;
     case 0x081C:
         /* system control register */
@@ -523,7 +523,9 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
                           const char *kernel_filename, const char *kernel_cmdline,
                           const char *initrd_filename)
 {
+    CPUState *env;
     char buf[1024];
+    SetIRQFunc *set_irq;
     m48t59_t *nvram;
     int PPC_io_memory;
     int linux_boot, i, nb_nics1, bios_size;
@@ -537,6 +539,23 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
        return;
 
     linux_boot = (kernel_filename != NULL);
+    
+    /* init CPUs */
+
+    env = cpu_init();
+    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 (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);
 
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
@@ -584,18 +603,6 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
         initrd_size = 0;
     }
 
-    /* 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 (def == NULL) {
-        cpu_abort(cpu_single_env, "Unable to find PowerPC CPU definition\n");
-    }
-    cpu_ppc_register(cpu_single_env, def);
-    /* Set time-base frequency to 100 Mhz */
-    cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL);
-
     isa_mem_base = 0xc0000000;
     pci_bus = pci_prep_init();
     //    pci_bus = i440fx_init();
@@ -609,10 +616,10 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
                    vga_ram_size, 0, 0);
     rtc_init(0x70, 8);
     //    openpic = openpic_init(0x00000000, 0xF0000000, 1);
-    isa_pic = pic_init(pic_irq_request, cpu_single_env);
+    isa_pic = pic_init(pic_irq_request, first_cpu);
     //    pit = pit_init(0x40, 0);
 
-    serial_init(0x3f8, 4, serial_hds[0]);
+    serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
     nb_nics1 = nb_nics;
     if (nb_nics1 > NE2000_NB_MAX)
         nb_nics1 = NE2000_NB_MAX;
@@ -652,7 +659,7 @@ static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
     cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory);
 #endif
 
-    nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE);
+    nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59);
     if (nvram == NULL)
         return;
     sysctrl->nvram = nvram;
diff --git a/qemu/hw/ps2.c b/qemu/hw/ps2.c
new file mode 100644 (file)
index 0000000..e7c66f6
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+ * 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
+ * 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 PC keyboard */
+//#define DEBUG_KBD
+
+/* debug PC keyboard : only mouse */
+//#define DEBUG_MOUSE
+
+/* Keyboard Commands */
+#define KBD_CMD_SET_LEDS       0xED    /* Set keyboard leds */
+#define KBD_CMD_ECHO           0xEE
+#define KBD_CMD_GET_ID                 0xF2    /* get keyboard ID */
+#define KBD_CMD_SET_RATE       0xF3    /* Set typematic rate */
+#define KBD_CMD_ENABLE         0xF4    /* Enable scanning */
+#define KBD_CMD_RESET_DISABLE  0xF5    /* reset and disable scanning */
+#define KBD_CMD_RESET_ENABLE           0xF6    /* reset and enable scanning */
+#define KBD_CMD_RESET          0xFF    /* Reset */
+
+/* Keyboard Replies */
+#define KBD_REPLY_POR          0xAA    /* Power on reset */
+#define KBD_REPLY_ACK          0xFA    /* Command ACK */
+#define KBD_REPLY_RESEND       0xFE    /* Command NACK, send the cmd again */
+
+/* Mouse Commands */
+#define AUX_SET_SCALE11                0xE6    /* Set 1:1 scaling */
+#define AUX_SET_SCALE21                0xE7    /* Set 2:1 scaling */
+#define AUX_SET_RES            0xE8    /* Set resolution */
+#define AUX_GET_SCALE          0xE9    /* Get scaling factor */
+#define AUX_SET_STREAM         0xEA    /* Set stream mode */
+#define AUX_POLL               0xEB    /* Poll */
+#define AUX_RESET_WRAP         0xEC    /* Reset wrap mode */
+#define AUX_SET_WRAP           0xEE    /* Set wrap mode */
+#define AUX_SET_REMOTE         0xF0    /* Set remote mode */
+#define AUX_GET_TYPE           0xF2    /* Get type */
+#define AUX_SET_SAMPLE         0xF3    /* Set sample rate */
+#define AUX_ENABLE_DEV         0xF4    /* Enable aux device */
+#define AUX_DISABLE_DEV                0xF5    /* Disable aux device */
+#define AUX_SET_DEFAULT                0xF6
+#define AUX_RESET              0xFF    /* Reset aux device */
+#define AUX_ACK                        0xFA    /* Command byte ACK. */
+
+#define MOUSE_STATUS_REMOTE     0x40
+#define MOUSE_STATUS_ENABLED    0x20
+#define MOUSE_STATUS_SCALE21    0x10
+
+#define PS2_QUEUE_SIZE 256
+
+typedef struct {
+    uint8_t data[PS2_QUEUE_SIZE];
+    int rptr, wptr, count;
+} PS2Queue;
+
+typedef struct {
+    PS2Queue queue;
+    int32_t write_cmd;
+    void (*update_irq)(void *, int);
+    void *update_arg;
+} PS2State;
+
+typedef struct {
+    PS2State common;
+    int scan_enabled;
+} PS2KbdState;
+
+typedef struct {
+    PS2State common;
+    uint8_t mouse_status;
+    uint8_t mouse_resolution;
+    uint8_t mouse_sample_rate;
+    uint8_t mouse_wrap;
+    uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
+    uint8_t mouse_detect_state;
+    int mouse_dx; /* current values, needed for 'poll' mode */
+    int mouse_dy;
+    int mouse_dz;
+    uint8_t mouse_buttons;
+} PS2MouseState;
+
+void ps2_queue(void *opaque, int b)
+{
+    PS2State *s = (PS2State *)opaque;
+    PS2Queue *q = &s->queue;
+
+    if (q->count >= PS2_QUEUE_SIZE)
+        return;
+    q->data[q->wptr] = b;
+    if (++q->wptr == PS2_QUEUE_SIZE)
+        q->wptr = 0;
+    q->count++;
+    s->update_irq(s->update_arg, 1);
+}
+
+static void ps2_put_keycode(void *opaque, int keycode)
+{
+    PS2MouseState *s = opaque;
+    ps2_queue(&s->common, keycode);
+}
+
+uint32_t ps2_read_data(void *opaque)
+{
+    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
+           (needed for EMM386) */
+        /* XXX: need a timer to do things correctly */
+        index = q->rptr - 1;
+        if (index < 0)
+            index = PS2_QUEUE_SIZE - 1;
+        val = q->data[index];
+    } else {
+        val = q->data[q->rptr];
+        if (++q->rptr == PS2_QUEUE_SIZE)
+            q->rptr = 0;
+        q->count--;
+        /* reading deasserts IRQ */
+        s->update_irq(s->update_arg, 0);
+        /* reassert IRQs if data left */
+        s->update_irq(s->update_arg, q->count != 0);
+    }
+    return val;
+}
+
+static void ps2_reset_keyboard(PS2KbdState *s)
+{
+    s->scan_enabled = 1;
+}
+
+void ps2_write_keyboard(void *opaque, int val)
+{
+    PS2KbdState *s = (PS2KbdState *)opaque;
+
+    switch(s->common.write_cmd) {
+    default:
+    case -1:
+        switch(val) {
+        case 0x00:
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case 0x05:
+            ps2_queue(&s->common, KBD_REPLY_RESEND);
+            break;
+        case KBD_CMD_GET_ID:
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            ps2_queue(&s->common, 0xab);
+            ps2_queue(&s->common, 0x83);
+            break;
+        case KBD_CMD_ECHO:
+            ps2_queue(&s->common, KBD_CMD_ECHO);
+            break;
+        case KBD_CMD_ENABLE:
+            s->scan_enabled = 1;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case KBD_CMD_SET_LEDS:
+        case KBD_CMD_SET_RATE:
+            s->common.write_cmd = val;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case KBD_CMD_RESET_DISABLE:
+            ps2_reset_keyboard(s);
+            s->scan_enabled = 0;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case KBD_CMD_RESET_ENABLE:
+            ps2_reset_keyboard(s);
+            s->scan_enabled = 1;
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        case KBD_CMD_RESET:
+            ps2_reset_keyboard(s);
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            ps2_queue(&s->common, KBD_REPLY_POR);
+            break;
+        default:
+            ps2_queue(&s->common, KBD_REPLY_ACK);
+            break;
+        }
+        break;
+    case KBD_CMD_SET_LEDS:
+        ps2_queue(&s->common, KBD_REPLY_ACK);
+        s->common.write_cmd = -1;
+        break;
+    case KBD_CMD_SET_RATE:
+        ps2_queue(&s->common, KBD_REPLY_ACK);
+        s->common.write_cmd = -1;
+        break;
+    }
+}
+
+static void ps2_mouse_send_packet(PS2MouseState *s)
+{
+    unsigned int b;
+    int dx1, dy1, dz1;
+
+    dx1 = s->mouse_dx;
+    dy1 = s->mouse_dy;
+    dz1 = s->mouse_dz;
+    /* XXX: increase range to 8 bits ? */
+    if (dx1 > 127)
+        dx1 = 127;
+    else if (dx1 < -127)
+        dx1 = -127;
+    if (dy1 > 127)
+        dy1 = 127;
+    else if (dy1 < -127)
+        dy1 = -127;
+    b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
+    ps2_queue(&s->common, b);
+    ps2_queue(&s->common, dx1 & 0xff);
+    ps2_queue(&s->common, dy1 & 0xff);
+    /* extra byte for IMPS/2 or IMEX */
+    switch(s->mouse_type) {
+    default:
+        break;
+    case 3:
+        if (dz1 > 127)
+            dz1 = 127;
+        else if (dz1 < -127)
+                dz1 = -127;
+        ps2_queue(&s->common, dz1 & 0xff);
+        break;
+    case 4:
+        if (dz1 > 7)
+            dz1 = 7;
+        else if (dz1 < -7)
+            dz1 = -7;
+        b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
+        ps2_queue(&s->common, b);
+        break;
+    }
+
+    /* update deltas */
+    s->mouse_dx -= dx1;
+    s->mouse_dy -= dy1;
+    s->mouse_dz -= dz1;
+}
+
+static void ps2_mouse_event(void *opaque, 
+                            int dx, int dy, int dz, int buttons_state)
+{
+    PS2MouseState *s = opaque;
+
+    /* check if deltas are recorded when disabled */
+    if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
+        return;
+
+    s->mouse_dx += dx;
+    s->mouse_dy -= dy;
+    s->mouse_dz += dz;
+    /* XXX: SDL sometimes generates nul events: we delete them */
+    if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
+        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(;;) {
+            /* if not remote, send event. Multiple events are sent if
+               too big deltas */
+            ps2_mouse_send_packet(s);
+            if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
+                break;
+        }
+    }
+}
+
+void ps2_write_mouse(void *opaque, int val)
+{
+    PS2MouseState *s = (PS2MouseState *)opaque;
+#ifdef DEBUG_MOUSE
+    printf("kbd: write mouse 0x%02x\n", val);
+#endif
+    switch(s->common.write_cmd) {
+    default:
+    case -1:
+        /* mouse command */
+        if (s->mouse_wrap) {
+            if (val == AUX_RESET_WRAP) {
+                s->mouse_wrap = 0;
+                ps2_queue(&s->common, AUX_ACK);
+                return;
+            } else if (val != AUX_RESET) {
+                ps2_queue(&s->common, val);
+                return;
+            }
+        }
+        switch(val) {
+        case AUX_SET_SCALE11:
+            s->mouse_status &= ~MOUSE_STATUS_SCALE21;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_SCALE21:
+            s->mouse_status |= MOUSE_STATUS_SCALE21;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_STREAM:
+            s->mouse_status &= ~MOUSE_STATUS_REMOTE;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_WRAP:
+            s->mouse_wrap = 1;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_REMOTE:
+            s->mouse_status |= MOUSE_STATUS_REMOTE;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_GET_TYPE:
+            ps2_queue(&s->common, AUX_ACK);
+            ps2_queue(&s->common, s->mouse_type);
+            break;
+        case AUX_SET_RES:
+        case AUX_SET_SAMPLE:
+            s->common.write_cmd = val;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_GET_SCALE:
+            ps2_queue(&s->common, AUX_ACK);
+            ps2_queue(&s->common, s->mouse_status);
+            ps2_queue(&s->common, s->mouse_resolution);
+            ps2_queue(&s->common, s->mouse_sample_rate);
+            break;
+        case AUX_POLL:
+            ps2_queue(&s->common, AUX_ACK);
+            ps2_mouse_send_packet(s);
+            break;
+        case AUX_ENABLE_DEV:
+            s->mouse_status |= MOUSE_STATUS_ENABLED;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_DISABLE_DEV:
+            s->mouse_status &= ~MOUSE_STATUS_ENABLED;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_SET_DEFAULT:
+            s->mouse_sample_rate = 100;
+            s->mouse_resolution = 2;
+            s->mouse_status = 0;
+            ps2_queue(&s->common, AUX_ACK);
+            break;
+        case AUX_RESET:
+            s->mouse_sample_rate = 100;
+            s->mouse_resolution = 2;
+            s->mouse_status = 0;
+            s->mouse_type = 0;
+            ps2_queue(&s->common, AUX_ACK);
+            ps2_queue(&s->common, 0xaa);
+            ps2_queue(&s->common, s->mouse_type);
+            break;
+        default:
+            break;
+        }
+        break;
+    case AUX_SET_SAMPLE:
+        s->mouse_sample_rate = val;
+        /* detect IMPS/2 or IMEX */
+        switch(s->mouse_detect_state) {
+        default:
+        case 0:
+            if (val == 200)
+                s->mouse_detect_state = 1;
+            break;
+        case 1:
+            if (val == 100)
+                s->mouse_detect_state = 2;
+            else if (val == 200)
+                s->mouse_detect_state = 3;
+            else
+                s->mouse_detect_state = 0;
+            break;
+        case 2:
+            if (val == 80) 
+                s->mouse_type = 3; /* IMPS/2 */
+            s->mouse_detect_state = 0;
+            break;
+        case 3:
+            if (val == 80) 
+                s->mouse_type = 4; /* IMEX */
+            s->mouse_detect_state = 0;
+            break;
+        }
+        ps2_queue(&s->common, AUX_ACK);
+        s->common.write_cmd = -1;
+        break;
+    case AUX_SET_RES:
+        s->mouse_resolution = val;
+        ps2_queue(&s->common, AUX_ACK);
+        s->common.write_cmd = -1;
+        break;
+    }
+}
+
+static void ps2_reset(void *opaque)
+{
+    PS2State *s = (PS2State *)opaque;
+    PS2Queue *q;
+    s->write_cmd = -1;
+    q = &s->queue;
+    q->rptr = 0;
+    q->wptr = 0;
+    q->count = 0;
+}
+
+static void ps2_kbd_save(QEMUFile* f, void* opaque)
+{
+    PS2KbdState *s = (PS2KbdState*)opaque;
+    
+    qemu_put_be32s(f, &s->common.write_cmd);
+    qemu_put_be32s(f, &s->scan_enabled);
+}
+
+static void ps2_mouse_save(QEMUFile* f, void* opaque)
+{
+    PS2MouseState *s = (PS2MouseState*)opaque;
+    
+    qemu_put_be32s(f, &s->common.write_cmd);
+    qemu_put_8s(f, &s->mouse_status);
+    qemu_put_8s(f, &s->mouse_resolution);
+    qemu_put_8s(f, &s->mouse_sample_rate);
+    qemu_put_8s(f, &s->mouse_wrap);
+    qemu_put_8s(f, &s->mouse_type);
+    qemu_put_8s(f, &s->mouse_detect_state);
+    qemu_put_be32s(f, &s->mouse_dx);
+    qemu_put_be32s(f, &s->mouse_dy);
+    qemu_put_be32s(f, &s->mouse_dz);
+    qemu_put_8s(f, &s->mouse_buttons);
+}
+
+static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id)
+{
+    PS2KbdState *s = (PS2KbdState*)opaque;
+    
+    if (version_id != 1)
+        return -EINVAL;
+    qemu_get_be32s(f, &s->common.write_cmd);
+    qemu_get_be32s(f, &s->scan_enabled);
+    return 0;
+}
+
+static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id)
+{
+    PS2MouseState *s = (PS2MouseState*)opaque;
+    
+    if (version_id != 1)
+        return -EINVAL;
+    qemu_get_be32s(f, &s->common.write_cmd);
+    qemu_get_8s(f, &s->mouse_status);
+    qemu_get_8s(f, &s->mouse_resolution);
+    qemu_get_8s(f, &s->mouse_sample_rate);
+    qemu_get_8s(f, &s->mouse_wrap);
+    qemu_get_8s(f, &s->mouse_type);
+    qemu_get_8s(f, &s->mouse_detect_state);
+    qemu_get_be32s(f, &s->mouse_dx);
+    qemu_get_be32s(f, &s->mouse_dy);
+    qemu_get_be32s(f, &s->mouse_dz);
+    qemu_get_8s(f, &s->mouse_buttons);
+    return 0;
+}
+
+void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
+{
+    PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState));
+
+    s->common.update_irq = update_irq;
+    s->common.update_arg = update_arg;
+    ps2_reset(&s->common);
+    register_savevm("ps2kbd", 0, 1, ps2_kbd_save, ps2_kbd_load, s);
+    qemu_add_kbd_event_handler(ps2_put_keycode, s);
+    qemu_register_reset(ps2_reset, &s->common);
+    return s;
+}
+
+void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
+{
+    PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState));
+
+    s->common.update_irq = update_irq;
+    s->common.update_arg = update_arg;
+    ps2_reset(&s->common);
+    register_savevm("ps2mouse", 0, 1, ps2_mouse_save, ps2_mouse_load, s);
+    qemu_add_mouse_event_handler(ps2_mouse_event, s);
+    qemu_register_reset(ps2_reset, &s->common);
+    return s;
+}
index bca5795..f7b12e6 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * QEMU Soundblaster 16 emulation
- * 
- * Copyright (c) 2003-2004 Vassili Karpov (malc)
- * 
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
  * 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
@@ -53,6 +53,7 @@ static struct {
 } conf = {5, 4, 5, 1, 5, 0x220};
 
 typedef struct SB16State {
+    QEMUSoundCard card;
     int irq;
     int dma;
     int hdma;
@@ -99,16 +100,16 @@ typedef struct SB16State {
     int dma_running;
     int bytes_per_second;
     int align;
-    SWVoice *voice;
+    int audio_free;
+    SWVoiceOut *voice;
 
-    QEMUTimer *ts, *aux_ts;
+    QEMUTimer *aux_ts;
     /* mixer state */
     int mixer_nreg;
     uint8_t mixer_regs[256];
 } SB16State;
 
-/* XXX: suppress that and use a context */
-static struct SB16State dsp;
+static void SB_audio_callback (void *opaque, int free);
 
 static int magic_of_irq (int irq)
 {
@@ -174,11 +175,11 @@ static void control (SB16State *s, int hold)
 
     if (hold) {
         DMA_hold_DREQ (dma);
-        AUD_enable (s->voice, 1);
+        AUD_set_active_out (s->voice, 1);
     }
     else {
         DMA_release_DREQ (dma);
-        AUD_enable (s->voice, 0);
+        AUD_set_active_out (s->voice, 0);
     }
 }
 
@@ -207,8 +208,9 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len)
         s->freq = (1000000 + (tmp / 2)) / tmp;
     }
 
-    if (dma_len != -1)
+    if (dma_len != -1) {
         s->block_size = dma_len << s->fmt_stereo;
+    }
     else {
         /* This is apparently the only way to make both Act1/PL
            and SecondReality/FC work
@@ -227,17 +229,35 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len)
     s->dma_auto = (mask & DMA8_AUTO) != 0;
     s->align = (1 << s->fmt_stereo) - 1;
 
-    if (s->block_size & s->align)
-        dolog ("warning: unaligned buffer\n");
+    if (s->block_size & s->align) {
+        dolog ("warning: misaligned block size %d, alignment %d\n",
+               s->block_size, s->align + 1);
+    }
 
     ldebug ("freq %d, stereo %d, sign %d, bits %d, "
             "dma %d, auto %d, fifo %d, high %d\n",
             s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
             s->block_size, s->dma_auto, s->fifo, s->highspeed);
 
-    if (s->freq)
-        s->voice = AUD_open (s->voice, "sb16", s->freq,
-                             1 << s->fmt_stereo, s->fmt);
+    if (s->freq) {
+        audsettings_t as;
+
+        s->audio_free = 0;
+
+        as.freq = s->freq;
+        as.nchannels = 1 << s->fmt_stereo;
+        as.fmt = s->fmt;
+
+        s->voice = AUD_open_out (
+            &s->card,
+            s->voice,
+            "sb16",
+            s,
+            SB_audio_callback,
+            &as,
+            0                   /* little endian */
+            );
+    }
 
     control (s, 1);
     speaker (s, 1);
@@ -309,12 +329,30 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)
     s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16);
     s->highspeed = 0;
     s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1;
-    if (s->block_size & s->align)
-        dolog ("warning: unaligned buffer\n");
+    if (s->block_size & s->align) {
+        dolog ("warning: misaligned block size %d, alignment %d\n",
+               s->block_size, s->align + 1);
+    }
+
+    if (s->freq) {
+        audsettings_t as;
+
+        s->audio_free = 0;
 
-    if (s->freq)
-        s->voice = AUD_open (s->voice, "sb16", s->freq,
-                             1 << s->fmt_stereo, s->fmt);
+        as.freq = s->freq;
+        as.nchannels = 1 << s->fmt_stereo;
+        as.fmt = s->fmt;
+
+        s->voice = AUD_open_out (
+            &s->card,
+            s->voice,
+            "sb16",
+            s,
+            SB_audio_callback,
+            &as,
+            0                   /* little endian */
+            );
+    }
 
     control (s, 1);
     speaker (s, 1);
@@ -323,14 +361,16 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)
 static inline void dsp_out_data (SB16State *s, uint8_t val)
 {
     ldebug ("outdata %#x\n", val);
-    if (s->out_data_len < sizeof (s->out_data))
+    if ((size_t) s->out_data_len < sizeof (s->out_data)) {
         s->out_data[s->out_data_len++] = val;
+    }
 }
 
 static inline uint8_t dsp_get_data (SB16State *s)
 {
-    if (s->in_index)
+    if (s->in_index) {
         return s->in2_data[--s->in_index];
+    }
     else {
         dolog ("buffer underflow\n");
         return 0;
@@ -356,6 +396,8 @@ static void command (SB16State *s, uint8_t cmd)
         s->needed_bytes = 3;
     }
     else {
+        s->needed_bytes = 0;
+
         switch (cmd) {
         case 0x03:
             dsp_out_data (s, 0x10); /* s->csp_param); */
@@ -403,7 +445,7 @@ static void command (SB16State *s, uint8_t cmd)
             goto warn;
 
         case 0x35:
-            dolog ("MIDI command(0x35) not implemented\n");
+            dolog ("0x35 - MIDI command not implemented\n");
             break;
 
         case 0x40:
@@ -435,6 +477,38 @@ static void command (SB16State *s, uint8_t cmd)
             s->needed_bytes = 2;
             break;
 
+        case 0x74:
+            s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
+            dolog ("0x75 - DMA DAC, 4-bit ADPCM not implemented\n");
+            break;
+
+        case 0x75:              /* DMA DAC, 4-bit ADPCM Reference */
+            s->needed_bytes = 2;
+            dolog ("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n");
+            break;
+
+        case 0x76:              /* DMA DAC, 2.6-bit ADPCM */
+            s->needed_bytes = 2;
+            dolog ("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n");
+            break;
+
+        case 0x77:              /* DMA DAC, 2.6-bit ADPCM Reference */
+            s->needed_bytes = 2;
+            dolog ("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n");
+            break;
+
+        case 0x7d:
+            dolog ("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n");
+            dolog ("not implemented\n");
+            break;
+
+        case 0x7f:
+            dolog (
+                "0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"
+                );
+            dolog ("not implemented\n");
+            break;
+
         case 0x80:
             s->needed_bytes = 2;
             break;
@@ -476,9 +550,9 @@ static void command (SB16State *s, uint8_t cmd)
             s->dma_auto = 0;
             break;
 
-        case 0xe0:
+        case 0xe0:              /* DSP identification */
             s->needed_bytes = 1;
-            goto warn;
+            break;
 
         case 0xe1:
             dsp_out_data (s, s->ver & 0xff);
@@ -503,7 +577,7 @@ static void command (SB16State *s, uint8_t cmd)
 
         case 0xe7:
             dolog ("Attempt to probe for ESS (0xe7)?\n");
-            return;
+            break;
 
         case 0xe8:              /* read test reg */
             dsp_out_data (s, s->test_reg);
@@ -529,21 +603,29 @@ static void command (SB16State *s, uint8_t cmd)
             goto warn;
 
         default:
-            dolog ("unrecognized command %#x\n", cmd);
-            return;
+            dolog ("Unrecognized command %#x\n", cmd);
+            break;
         }
     }
 
-    s->cmd = cmd;
-    if (!s->needed_bytes)
+    if (!s->needed_bytes) {
         ldebug ("\n");
+    }
+
+ exit:
+    if (!s->needed_bytes) {
+        s->cmd = -1;
+    }
+    else {
+        s->cmd = cmd;
+    }
     return;
 
  warn:
     dolog ("warning: command %#x,%d is not truly understood yet\n",
            cmd, s->needed_bytes);
-    s->cmd = cmd;
-    return;
+    goto exit;
+
 }
 
 static uint16_t dsp_get_lohi (SB16State *s)
@@ -607,8 +689,9 @@ static void complete (SB16State *s)
                 s->csp_reg83[s->csp_reg83r % 4] = d0;
                 s->csp_reg83r += 1;
             }
-            else
+            else {
                 s->csp_regs[d1] = d0;
+            }
             break;
 
         case 0x0f:
@@ -622,8 +705,9 @@ static void complete (SB16State *s)
                 dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]);
                 s->csp_reg83w += 1;
             }
-            else
+            else {
                 dsp_out_data (s, s->csp_regs[d0]);
+            }
             break;
 
         case 0x10:
@@ -641,8 +725,9 @@ static void complete (SB16State *s)
             break;
 
         case 0x42:              /* FT2 sets output freq with this, go figure */
+#if 0
             dolog ("cmd 0x42 might not do what it think it should\n");
-
+#endif
         case 0x41:
             s->freq = dsp_get_hilo (s);
             ldebug ("set freq %d\n", s->freq);
@@ -653,6 +738,13 @@ static void complete (SB16State *s)
             ldebug ("set dma block len %d\n", s->block_size);
             break;
 
+        case 0x74:
+        case 0x75:
+        case 0x76:
+        case 0x77:
+            /* ADPCM stuff, ignore */
+            break;
+
         case 0x80:
             {
                 int freq, samples, bytes;
@@ -662,10 +754,17 @@ static void complete (SB16State *s)
                 samples = dsp_get_lohi (s) + 1;
                 bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
                 ticks = (bytes * ticks_per_sec) / freq;
-                if (ticks < ticks_per_sec / 1024)
+                if (ticks < ticks_per_sec / 1024) {
                     pic_set_irq (s->irq, 1);
-                else
-                    qemu_mod_timer (s->aux_ts, qemu_get_clock (vm_clock) + ticks);
+                }
+                else {
+                    if (s->aux_ts) {
+                        qemu_mod_timer (
+                            s->aux_ts,
+                            qemu_get_clock (vm_clock) + ticks
+                            );
+                    }
+                }
                 ldebug ("mix silence %d %d %lld\n", samples, bytes, ticks);
             }
             break;
@@ -674,7 +773,7 @@ static void complete (SB16State *s)
             d0 = dsp_get_data (s);
             s->out_data_len = 0;
             ldebug ("E0 data = %#x\n", d0);
-            dsp_out_data(s, ~d0);
+            dsp_out_data (s, ~d0);
             break;
 
         case 0xe2:
@@ -737,6 +836,7 @@ static void reset (SB16State *s)
     s->nzero = 0;
     s->highspeed = 0;
     s->v2x6 = 0;
+    s->cmd = -1;
 
     dsp_out_data(s, 0xaa);
     speaker (s, 0);
@@ -761,8 +861,9 @@ static IO_WRITE_PROTO (dsp_write)
                     pic_set_irq (s->irq, 0);
                     control (s, 0);
                 }
-                else
+                else {
                     reset (s);
+                }
             }
             s->v2x6 = 0;
             break;
@@ -845,7 +946,10 @@ static IO_READ_PROTO (dsp_read)
             s->last_read_byte = retval;
         }
         else {
-            dolog ("empty output buffer\n");
+            if (s->cmd != -1) {
+                dolog ("empty output buffer for command %#x\n",
+                       s->cmd);
+            }
             retval = s->last_read_byte;
             /* goto error; */
         }
@@ -882,13 +986,14 @@ static IO_READ_PROTO (dsp_read)
         goto error;
     }
 
-    if (!ack)
+    if (!ack) {
         ldebug ("read %#x -> %#x\n", nport, retval);
+    }
 
     return retval;
 
  error:
-    dolog ("WARNING dsp_read %#x error\n", nport);
+    dolog ("warning: dsp_read %#x error\n", nport);
     return 0xff;
 }
 
@@ -925,6 +1030,7 @@ static void reset_mixer (SB16State *s)
 static IO_WRITE_PROTO(mixer_write_indexb)
 {
     SB16State *s = opaque;
+    (void) nport;
     s->mixer_nreg = val;
 }
 
@@ -932,9 +1038,8 @@ static IO_WRITE_PROTO(mixer_write_datab)
 {
     SB16State *s = opaque;
 
+    (void) nport;
     ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val);
-    if (s->mixer_nreg > sizeof (s->mixer_regs))
-        return;
 
     switch (s->mixer_nreg) {
     case 0x00:
@@ -945,8 +1050,9 @@ static IO_WRITE_PROTO(mixer_write_datab)
         {
             int irq = irq_of_magic (val);
             ldebug ("setting irq to %d (val=%#x)\n", irq, val);
-            if (irq > 0)
+            if (irq > 0) {
                 s->irq = irq;
+            }
         }
         break;
 
@@ -956,8 +1062,12 @@ static IO_WRITE_PROTO(mixer_write_datab)
 
             dma = lsbindex (val & 0xf);
             hdma = lsbindex (val & 0xf0);
-            dolog ("attempt to set DMA register 8bit %d, 16bit %d (val=%#x)\n",
-                   dma, hdma, val);
+            if (dma != s->dma || hdma != s->hdma) {
+                dolog (
+                    "attempt to change DMA "
+                    "8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
+                    dma, s->dma, hdma, s->hdma, val);
+            }
 #if 0
             s->dma = dma;
             s->hdma = hdma;
@@ -971,8 +1081,9 @@ static IO_WRITE_PROTO(mixer_write_datab)
         return;
 
     default:
-        if (s->mixer_nreg >= 0x80)
-            dolog ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val);
+        if (s->mixer_nreg >= 0x80) {
+            ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val);
+        }
         break;
     }
 
@@ -988,11 +1099,17 @@ static IO_WRITE_PROTO(mixer_write_indexw)
 static IO_READ_PROTO(mixer_read)
 {
     SB16State *s = opaque;
+
+    (void) nport;
 #ifndef DEBUG_SB16_MOST
-    if (s->mixer_nreg != 0x82)
-#endif
+    if (s->mixer_nreg != 0x82) {
+        ldebug ("mixer_read[%#x] -> %#x\n",
+                s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
+    }
+#else
     ldebug ("mixer_read[%#x] -> %#x\n",
             s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
+#endif
     return s->mixer_regs[s->mixer_nreg];
 }
 
@@ -1007,11 +1124,13 @@ static int write_audio (SB16State *s, int nchan, int dma_pos,
 
     while (temp) {
         int left = dma_len - dma_pos;
-        int to_copy, copied;
+        int copied;
+        size_t to_copy;
 
         to_copy = audio_MIN (temp, left);
-        if (to_copy > sizeof(tmpbuf))
-            to_copy = sizeof(tmpbuf);
+        if (to_copy > sizeof (tmpbuf)) {
+            to_copy = sizeof (tmpbuf);
+        }
 
         copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
         copied = AUD_write (s->voice, tmpbuf, copied);
@@ -1020,8 +1139,9 @@ static int write_audio (SB16State *s, int nchan, int dma_pos,
         dma_pos = (dma_pos + copied) % dma_len;
         net += copied;
 
-        if (!copied)
+        if (!copied) {
             break;
+        }
     }
 
     return net;
@@ -1030,27 +1150,28 @@ static int write_audio (SB16State *s, int nchan, int dma_pos,
 static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
 {
     SB16State *s = opaque;
-    int free, rfree, till, copy, written, elapsed;
+    int till, copy, written, free;
 
     if (s->left_till_irq < 0) {
         s->left_till_irq = s->block_size;
     }
 
-    elapsed = AUD_calc_elapsed (s->voice);
-    free = elapsed;/* AUD_get_free (s->voice); */
-    rfree = free;
-    free = audio_MIN (free, elapsed) & ~s->align;
-
-    if ((free <= 0) || !dma_len) {
-        return dma_pos;
+    if (s->voice) {
+        free = s->audio_free & ~s->align;
+        if ((free <= 0) || !dma_len) {
+            return dma_pos;
+        }
+    }
+    else {
+        free = dma_len;
     }
 
     copy = free;
     till = s->left_till_irq;
 
 #ifdef DEBUG_SB16_MOST
-    dolog ("pos:%06d free:%d,%d till:%d len:%d\n",
-           dma_pos, free, AUD_get_free (s->voice), till, dma_len);
+    dolog ("pos:%06d %d till:%d len:%d\n",
+           dma_pos, free, till, dma_len);
 #endif
 
     if (till <= copy) {
@@ -1082,15 +1203,13 @@ static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
         s->left_till_irq = s->block_size + s->left_till_irq;
     }
 
-    AUD_adjust (s->voice, written);
     return dma_pos;
 }
 
-void SB_timer (void *opaque)
+static void SB_audio_callback (void *opaque, int free)
 {
     SB16State *s = opaque;
-    AUD_run ();
-    qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
+    s->audio_free = free;
 }
 
 static void SB_save (QEMUFile *f, void *opaque)
@@ -1150,8 +1269,9 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id)
 {
     SB16State *s = opaque;
 
-    if (version_id != 1)
+    if (version_id != 1) {
         return -EINVAL;
+    }
 
     qemu_get_be32s (f, &s->irq);
     qemu_get_be32s (f, &s->dma);
@@ -1202,14 +1322,30 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id)
     qemu_get_buffer (f, s->mixer_regs, 256);
 
     if (s->voice) {
-        AUD_close (s->voice);
+        AUD_close_out (&s->card, s->voice);
         s->voice = NULL;
     }
 
     if (s->dma_running) {
-        if (s->freq)
-            s->voice = AUD_open (s->voice, "sb16", s->freq,
-                                 1 << s->fmt_stereo, s->fmt);
+        if (s->freq) {
+            audsettings_t as;
+
+            s->audio_free = 0;
+
+            as.freq = s->freq;
+            as.nchannels = 1 << s->fmt_stereo;
+            as.fmt = s->fmt;
+
+            s->voice = AUD_open_out (
+                &s->card,
+                s->voice,
+                "sb16",
+                s,
+                SB_audio_callback,
+                &as,
+                0               /* little endian */
+                );
+        }
 
         control (s, 1);
         speaker (s, s->speaker);
@@ -1217,17 +1353,26 @@ static int SB_load (QEMUFile *f, void *opaque, int version_id)
     return 0;
 }
 
-void SB16_init (void)
+int SB16_init (AudioState *audio)
 {
-    SB16State *s = &dsp;
+    SB16State *s;
     int i;
     static const uint8_t dsp_write_ports[] = {0x6, 0xc};
     static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf};
 
-    s->ts = qemu_new_timer (vm_clock, SB_timer, s);
-    if (!s->ts)
-        return;
+    if (!audio) {
+        dolog ("No audio state\n");
+        return -1;
+    }
 
+    s = qemu_mallocz (sizeof (*s));
+    if (!s) {
+        dolog ("Could not allocate memory for SB16 (%zu bytes)\n",
+               sizeof (*s));
+        return -1;
+    }
+
+    s->cmd = -1;
     s->irq = conf.irq;
     s->dma = conf.dma;
     s->hdma = conf.hdma;
@@ -1243,8 +1388,9 @@ void SB16_init (void)
 
     reset_mixer (s);
     s->aux_ts = qemu_new_timer (vm_clock, aux_timer, s);
-    if (!s->aux_ts)
-        return;
+    if (!s->aux_ts) {
+        dolog ("warning: Could not create auxiliary timer\n");
+    }
 
     for (i = 0; i < LENOFA (dsp_write_ports); i++) {
         register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s);
@@ -1263,6 +1409,7 @@ void SB16_init (void)
     DMA_register_channel (s->dma, SB_read_DMA, s);
     s->can_write = 1;
 
-    qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
     register_savevm ("sb16", 0, 1, SB_save, SB_load, s);
+    AUD_register_card (audio, "sb16", &s->card);
+    return 0;
 }
index 3fe482c..254434e 100644 (file)
@@ -83,8 +83,13 @@ struct SerialState {
     /* 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;
     CharDriverState *chr;
+    int last_break_enable;
+    target_ulong base;
+    int it_shift;
 };
 
 static void serial_update_irq(SerialState *s)
@@ -97,12 +102,44 @@ static void serial_update_irq(SerialState *s)
         s->iir = UART_IIR_NO_INT;
     }
     if (s->iir != UART_IIR_NO_INT) {
-        pic_set_irq(s->irq, 1);
+        s->set_irq(s->irq_opaque, s->irq, 1);
     } else {
-        pic_set_irq(s->irq, 0);
+        s->set_irq(s->irq_opaque, s->irq, 0);
     }
 }
 
+static void serial_update_parameters(SerialState *s)
+{
+    int speed, parity, data_bits, stop_bits;
+    QEMUSerialSetParams ssp;
+
+    if (s->lcr & 0x08) {
+        if (s->lcr & 0x10)
+            parity = 'E';
+        else
+            parity = 'O';
+    } else {
+            parity = 'N';
+    }
+    if (s->lcr & 0x04) 
+        stop_bits = 2;
+    else
+        stop_bits = 1;
+    data_bits = (s->lcr & 0x03) + 5;
+    if (s->divider == 0)
+        return;
+    speed = 115200 / s->divider;
+    ssp.speed = speed;
+    ssp.parity = parity;
+    ssp.data_bits = data_bits;
+    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", 
+           speed, parity, data_bits, stop_bits);
+#endif
+}
+
 static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 {
     SerialState *s = opaque;
@@ -117,6 +154,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     case 0:
         if (s->lcr & UART_LCR_DLAB) {
             s->divider = (s->divider & 0xff00) | val;
+            serial_update_parameters(s);
         } else {
             s->thr_ipending = 0;
             s->lsr &= ~UART_LSR_THRE;
@@ -132,6 +170,7 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     case 1:
         if (s->lcr & UART_LCR_DLAB) {
             s->divider = (s->divider & 0x00ff) | (val << 8);
+            serial_update_parameters(s);
         } else {
             s->ier = val & 0x0f;
             if (s->lsr & UART_LSR_THRE) {
@@ -143,7 +182,17 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
     case 2:
         break;
     case 3:
-        s->lcr = val;
+        {
+            int break_enable;
+            s->lcr = val;
+            serial_update_parameters(s);
+            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, 
+                               &break_enable);
+            }
+        }
         break;
     case 4:
         s->mcr = val & 0x1f;
@@ -258,18 +307,58 @@ static void serial_event(void *opaque, int event)
         serial_receive_break(s);
 }
 
+static void serial_save(QEMUFile *f, void *opaque)
+{
+    SerialState *s = opaque;
+
+    qemu_put_8s(f,&s->divider);
+    qemu_put_8s(f,&s->rbr);
+    qemu_put_8s(f,&s->ier);
+    qemu_put_8s(f,&s->iir);
+    qemu_put_8s(f,&s->lcr);
+    qemu_put_8s(f,&s->mcr);
+    qemu_put_8s(f,&s->lsr);
+    qemu_put_8s(f,&s->msr);
+    qemu_put_8s(f,&s->scr);
+}
+
+static int serial_load(QEMUFile *f, void *opaque, int version_id)
+{
+    SerialState *s = opaque;
+
+    if(version_id != 1)
+        return -EINVAL;
+
+    qemu_get_8s(f,&s->divider);
+    qemu_get_8s(f,&s->rbr);
+    qemu_get_8s(f,&s->ier);
+    qemu_get_8s(f,&s->iir);
+    qemu_get_8s(f,&s->lcr);
+    qemu_get_8s(f,&s->mcr);
+    qemu_get_8s(f,&s->lsr);
+    qemu_get_8s(f,&s->msr);
+    qemu_get_8s(f,&s->scr);
+
+    return 0;
+}
+
 /* If fd is zero, it means that the serial device uses the console */
-SerialState *serial_init(int base, int irq, CharDriverState *chr)
+SerialState *serial_init(SetIRQFunc *set_irq, void *opaque,
+                         int base, int 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;
 
+    register_savevm("serial", base, 1, serial_save, serial_load, s);
+
     register_ioport_write(base, 8, 1, serial_ioport_write, s);
     register_ioport_read(base, 8, 1, serial_ioport_read, s);
     s->chr = chr;
@@ -277,3 +366,90 @@ SerialState *serial_init(int base, int irq, CharDriverState *chr)
     qemu_chr_add_event_handler(chr, serial_event);
     return s;
 }
+
+/* Memory mapped interface */
+static 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)
+{
+    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)
+{
+    SerialState *s = opaque;
+
+    return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF;
+}
+
+static void serial_mm_writew (void *opaque,
+                              target_phys_addr_t addr, uint32_t value)
+{
+    SerialState *s = opaque;
+
+    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)
+{
+    SerialState *s = opaque;
+
+    return serial_ioport_read(s, (addr - s->base) >> s->it_shift);
+}
+
+static void serial_mm_writel (void *opaque,
+                              target_phys_addr_t addr, uint32_t value)
+{
+    SerialState *s = opaque;
+
+    serial_ioport_write(s, (addr - s->base) >> s->it_shift, value);
+}
+
+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,
+};
+
+SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque,
+                             target_ulong base, int it_shift,
+                             int irq, CharDriverState *chr)
+{
+    SerialState *s;
+    int s_io_memory;
+
+    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;
+    s->base = base;
+    s->it_shift = it_shift;
+
+    register_savevm("serial", base, 1, 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);
+    s->chr = chr;
+    qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s);
+    qemu_chr_add_event_handler(chr, serial_event);
+    return s;
+}
index 8a5db5c..e43151f 100644 (file)
@@ -53,6 +53,7 @@ typedef struct SLAVIO_INTCTLState {
 #ifdef DEBUG_IRQ_COUNT
     uint64_t irq_count[32];
 #endif
+    CPUState *cpu_envs[MAX_CPUS];
 } SLAVIO_INTCTLState;
 
 #define INTCTL_MAXADDR 0xf
@@ -96,6 +97,7 @@ static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint
     case 2: // set softint
        val &= 0xfffe0000;
        s->intreg_pending[cpu] |= val;
+        slavio_check_interrupts(s);
        DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
        break;
     default:
@@ -213,9 +215,10 @@ static const uint32_t intbit_to_level[32] = {
 
 static void slavio_check_interrupts(void *opaque)
 {
+    CPUState *env;
     SLAVIO_INTCTLState *s = opaque;
     uint32_t pending = s->intregm_pending;
-    unsigned int i, max = 0;
+    unsigned int i, j, max = 0;
 
     pending &= ~s->intregm_disabled;
 
@@ -226,19 +229,52 @@ static void slavio_check_interrupts(void *opaque)
                    max = intbit_to_level[i];
            }
        }
-       if (cpu_single_env->interrupt_index == 0) {
-           DPRINTF("Triggered pil %d\n", max);
+        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]++;
+                s->irq_count[max]++;
 #endif
-           cpu_single_env->interrupt_index = TT_EXTINT | max;
-           cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+                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), pending exception %x\n", pending, cpu_single_env->interrupt_index);
     }
     else
        DPRINTF("Not triggered (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;
+            }
+        }
+       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);
+            }
+        }
+    }
 }
 
 /*
@@ -249,7 +285,7 @@ void slavio_pic_set_irq(void *opaque, int irq, int level)
 {
     SLAVIO_INTCTLState *s = opaque;
 
-    DPRINTF("Set irq %d level %d\n", irq, level);
+    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];
@@ -267,6 +303,29 @@ void slavio_pic_set_irq(void *opaque, int irq, int level)
     slavio_check_interrupts(s);
 }
 
+void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu)
+{
+    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);
+           }
+       }
+    }
+    slavio_check_interrupts(s);
+}
+
 static void slavio_intctl_save(QEMUFile *f, void *opaque)
 {
     SLAVIO_INTCTLState *s = opaque;
@@ -310,6 +369,12 @@ static void slavio_intctl_reset(void *opaque)
     s->target_cpu = 0;
 }
 
+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)
 {
     int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
index 597a0cb..904f44e 100644 (file)
@@ -44,7 +44,7 @@ typedef struct MiscState {
     int irq;
     uint8_t config;
     uint8_t aux1, aux2;
-    uint8_t diag, mctrl;
+    uint8_t diag, mctrl, sysctrl;
 } MiscState;
 
 #define MISC_MAXADDR 1
@@ -64,7 +64,7 @@ static void slavio_misc_reset(void *opaque)
 {
     MiscState *s = opaque;
 
-    // Diagnostic register not cleared in reset
+    // Diagnostic and system control registers not cleared in reset
     s->config = s->aux1 = s->aux2 = s->mctrl = 0;
 }
 
@@ -116,15 +116,16 @@ static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32
        break;
     case 0x1f00000:
        MISC_DPRINTF("Write system control %2.2x\n", val & 0xff);
-       if (val & 1)
+       if (val & 1) {
+           s->sysctrl = 0x2;
            qemu_system_reset_request();
+       }
        break;
     case 0xa000000:
        MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
 #if 0
-       // XXX: halting CPU does not work
-       raise_exception(EXCP_HLT);
-       cpu_loop_exit();
+        // XXX almost works
+        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
 #endif
        break;
     }
@@ -158,6 +159,7 @@ static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr)
        break;
     case 0x1f00000:
        MISC_DPRINTF("Read system control %2.2x\n", ret);
+       ret = s->sysctrl;
        break;
     case 0xa000000:
        MISC_DPRINTF("Read power management %2.2x\n", ret);
@@ -188,6 +190,7 @@ static void slavio_misc_save(QEMUFile *f, void *opaque)
     qemu_put_8s(f, &s->aux2);
     qemu_put_8s(f, &s->diag);
     qemu_put_8s(f, &s->mctrl);
+    qemu_put_8s(f, &s->sysctrl);
 }
 
 static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
@@ -203,6 +206,7 @@ static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
     qemu_get_8s(f, &s->aux2);
     qemu_get_8s(f, &s->diag);
     qemu_get_8s(f, &s->mctrl);
+    qemu_get_8s(f, &s->sysctrl);
     return 0;
 }
 
index 4b02d29..2b89c6d 100644 (file)
@@ -45,6 +45,8 @@
 #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
@@ -174,6 +176,50 @@ static void slavio_serial_reset(void *opaque)
     slavio_serial_reset_chn(&s->chn[1]);
 }
 
+static inline void clr_rxint(ChannelState *s)
+{
+    s->rxint = 0;
+    if (s->chn == 0)
+        s->rregs[3] &= ~0x20;
+    else {
+        s->otherchn->rregs[3] &= ~4;
+    }
+    slavio_serial_update_irq(s);
+}
+
+static inline void set_rxint(ChannelState *s)
+{
+    s->rxint = 1;
+    if (s->chn == 0)
+        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;
+    if (s->chn == 0)
+        s->rregs[3] &= ~0x10;
+    else {
+        s->otherchn->rregs[3] &= ~2;
+    }
+    slavio_serial_update_irq(s);
+}
+
+static inline void set_txint(ChannelState *s)
+{
+    s->txint = 1;
+    if (s->chn == 0)
+        s->rregs[3] |= 0x10;
+    else {
+        s->otherchn->rregs[3] |= 2;
+    }
+    slavio_serial_update_irq(s);
+}
+
 static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     SerialState *ser = opaque;
@@ -195,13 +241,17 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint
            val &= 0x38;
            switch (val) {
            case 8:
-               s->reg |= 0x8;
+               newreg |= 0x8;
                break;
            case 0x20:
-               s->rxint = 0;
+                clr_rxint(s);
                break;
            case 0x28:
-               s->txint = 0;
+                clr_txint(s);
+               break;
+           case 0x38:
+                clr_rxint(s);
+                clr_txint(s);
                break;
            default:
                break;
@@ -245,13 +295,9 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint
                handle_kbd_command(s, val);
            }
            s->txint = 1;
-           s->rregs[0] |= 4;
-           // Interrupts reported only on channel A
-           if (s->chn == 0)
-               s->rregs[3] |= 0x10;
-           else {
-               s->otherchn->rregs[3] |= 2;
-           }
+           s->rregs[0] |= 4; // Tx buffer empty
+           s->rregs[1] |= 1; // All sent
+            set_txint(s);
            slavio_serial_update_irq(s);
        }
        break;
@@ -278,12 +324,13 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
        s->reg = 0;
        return ret;
     case 1:
-       SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', s->rx);
        s->rregs[0] &= ~1;
+        clr_rxint(s);
        if (s->type == kbd)
            ret = get_queue(s);
        else
            ret = s->rx;
+       SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', ret);
        return ret;
     default:
        break;
@@ -303,16 +350,10 @@ static int serial_can_receive(void *opaque)
 
 static void serial_receive_byte(ChannelState *s, int ch)
 {
+    SER_DPRINTF("put ch %d\n", ch);
     s->rregs[0] |= 1;
-    // Interrupts reported only on channel A
-    if (s->chn == 0)
-       s->rregs[3] |= 0x20;
-    else {
-       s->otherchn->rregs[3] |= 4;
-    }
     s->rx = ch;
-    s->rxint = 1;
-    slavio_serial_update_irq(s);
+    set_rxint(s);
 }
 
 static void serial_receive_break(ChannelState *s)
@@ -454,7 +495,6 @@ static void handle_kbd_command(ChannelState *s, int val)
     switch (val) {
     case 1: // Reset, return type code
        put_queue(s, 0xff);
-       put_queue(s, 0xff);
        put_queue(s, 5); // Type 5
        break;
     case 7: // Query layout
index 47d5385..d75a76a 100644 (file)
@@ -42,6 +42,9 @@ do { printf("TIMER: " fmt , ##args); } while (0)
  * 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.
  *
+ * Per-CPU timers interrupt local CPU, system timer uses normal
+ * interrupt routing.
+ *
  */
 
 typedef struct SLAVIO_TIMERState {
@@ -53,11 +56,11 @@ typedef struct SLAVIO_TIMERState {
     int irq;
     int reached, stopped;
     int mode; // 0 = processor, 1 = user, 2 = system
+    unsigned int cpu;
 } SLAVIO_TIMERState;
 
 #define TIMER_MAXADDR 0x1f
 #define CNT_FREQ 2000000
-#define MAX_CPUS 16
 
 // Update count, set irq, update expire_time
 static void slavio_timer_get_out(SLAVIO_TIMERState *s)
@@ -73,7 +76,7 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s)
     else
        ticks = qemu_get_clock(vm_clock) - s->tick_offset;
 
-    out = (ticks >= s->expire_time);
+    out = (ticks > s->expire_time);
     if (out)
        s->reached = 0x80000000;
     if (!s->limit)
@@ -100,7 +103,7 @@ static void slavio_timer_get_out(SLAVIO_TIMERState *s)
     DPRINTF("irq %d limit %d reached %d d %lld count %d s->c %x diff %lld 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(s->irq, out);
+       pic_set_irq_cpu(s->irq, out, s->cpu);
 }
 
 // timer callback
@@ -127,7 +130,7 @@ static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
        // part of counter (user mode)
        if (s->mode != 1) {
            // clear irq
-           pic_set_irq(s->irq, 0);
+           pic_set_irq_cpu(s->irq, 0, s->cpu);
            s->count_load_time = qemu_get_clock(vm_clock);
            s->reached = 0;
            return s->limit;
@@ -263,7 +266,7 @@ static void slavio_timer_reset(void *opaque)
     slavio_timer_get_out(s);
 }
 
-static void slavio_timer_init_internal(uint32_t addr, int irq, int mode)
+void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu)
 {
     int slavio_timer_io_memory;
     SLAVIO_TIMERState *s;
@@ -273,6 +276,7 @@ static void slavio_timer_init_internal(uint32_t addr, int irq, int mode)
         return;
     s->irq = irq;
     s->mode = mode;
+    s->cpu = cpu;
     s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s);
 
     slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
@@ -282,14 +286,3 @@ static void slavio_timer_init_internal(uint32_t addr, int irq, int mode)
     qemu_register_reset(slavio_timer_reset, s);
     slavio_timer_reset(s);
 }
-
-void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2)
-{
-    int i;
-
-    for (i = 0; i < MAX_CPUS; i++) {
-       slavio_timer_init_internal(addr1 + i * TARGET_PAGE_SIZE, irq1, 0);
-    }
-
-    slavio_timer_init_internal(addr2, irq2, 2);
-}
diff --git a/qemu/hw/smc91c111.c b/qemu/hw/smc91c111.c
new file mode 100644 (file)
index 0000000..375debd
--- /dev/null
@@ -0,0 +1,702 @@
+/* 
+ * SMSC 91C111 Ethernet interface emulation
+ *
+ * Copyright (c) 2005 CodeSourcery, LLC.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the GPL
+ */
+
+#include "vl.h"
+/* For crc32 */
+#include <zlib.h>
+
+/* Number of 2k memory pages available.  */
+#define NUM_PACKETS 4
+
+typedef struct {
+    uint32_t base;
+    VLANClientState *vc;
+    uint16_t tcr;
+    uint16_t rcr;
+    uint16_t cr;
+    uint16_t ctr;
+    uint16_t gpr;
+    uint16_t ptr;
+    uint16_t ercv;
+    void *pic;
+    int irq;
+    int bank;
+    int packet_num;
+    int tx_alloc;
+    /* Bitmask of allocated packets.  */
+    int allocated;
+    int tx_fifo_len;
+    int tx_fifo[NUM_PACKETS];
+    int rx_fifo_len;
+    int rx_fifo[NUM_PACKETS];
+    int tx_fifo_done_len;
+    int tx_fifo_done[NUM_PACKETS];
+    /* Packet buffer memory.  */
+    uint8_t data[NUM_PACKETS][2048];
+    uint8_t int_level;
+    uint8_t int_mask;
+    uint8_t macaddr[6];
+} smc91c111_state;
+
+#define RCR_SOFT_RST  0x8000
+#define RCR_STRIP_CRC 0x0200
+#define RCR_RXEN      0x0100
+
+#define TCR_EPH_LOOP  0x2000
+#define TCR_NOCRC     0x0100
+#define TCR_PAD_EN    0x0080
+#define TCR_FORCOL    0x0004
+#define TCR_LOOP      0x0002
+#define TCR_TXEN      0x0001
+
+#define INT_MD        0x80
+#define INT_ERCV      0x40
+#define INT_EPH       0x20
+#define INT_RX_OVRN   0x10
+#define INT_ALLOC     0x08
+#define INT_TX_EMPTY  0x04
+#define INT_TX        0x02
+#define INT_RCV       0x01
+
+#define CTR_AUTO_RELEASE  0x0800
+#define CTR_RELOAD        0x0002
+#define CTR_STORE         0x0001
+
+#define RS_ALGNERR      0x8000
+#define RS_BRODCAST     0x4000
+#define RS_BADCRC       0x2000
+#define RS_ODDFRAME     0x1000
+#define RS_TOOLONG      0x0800
+#define RS_TOOSHORT     0x0400
+#define RS_MULTICAST    0x0001
+
+/* Update interrupt status.  */
+static void smc91c111_update(smc91c111_state *s)
+{
+    int level;
+
+    if (s->tx_fifo_len == 0)
+        s->int_level |= INT_TX_EMPTY;
+    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);
+}
+
+/* Try to allocate a packet.  Returns 0x80 on failure.  */
+static int smc91c111_allocate_packet(smc91c111_state *s)
+{
+    int i;
+    if (s->allocated == (1 << NUM_PACKETS) - 1) {
+        return 0x80;
+    }
+
+    for (i = 0; i < NUM_PACKETS; i++) {
+        if ((s->allocated & (1 << i)) == 0)
+            break;
+    }
+    s->allocated |= 1 << i;
+    return i;
+}
+
+
+/* Process a pending TX allocate.  */
+static void smc91c111_tx_alloc(smc91c111_state *s)
+{
+    s->tx_alloc = smc91c111_allocate_packet(s);
+    if (s->tx_alloc == 0x80)
+        return;
+    s->int_level |= INT_ALLOC;
+    smc91c111_update(s);
+}
+
+/* Remove and item from the RX FIFO.  */
+static void smc91c111_pop_rx_fifo(smc91c111_state *s)
+{
+    int i;
+
+    s->rx_fifo_len--;
+    if (s->rx_fifo_len) {
+        for (i = 0; i < s->rx_fifo_len; i++)
+            s->rx_fifo[i] = s->rx_fifo[i + 1];
+        s->int_level |= INT_RCV;
+    } else {
+        s->int_level &= ~INT_RCV;
+    }
+    smc91c111_update(s);
+}
+
+/* Remove an item from the TX completion FIFO.  */
+static void smc91c111_pop_tx_fifo_done(smc91c111_state *s)
+{
+    int i;
+
+    if (s->tx_fifo_done_len == 0)
+        return;
+    s->tx_fifo_done_len--;
+    for (i = 0; i < s->tx_fifo_done_len; i++)
+        s->tx_fifo_done[i] = s->tx_fifo_done[i + 1];
+}
+
+/* Release the memory allocated to a packet.  */
+static void smc91c111_release_packet(smc91c111_state *s, int packet)
+{
+    s->allocated &= ~(1 << packet);
+    if (s->tx_alloc == 0x80)
+        smc91c111_tx_alloc(s);
+}
+
+/* Flush the TX FIFO.  */
+static void smc91c111_do_tx(smc91c111_state *s)
+{
+    int i;
+    int len;
+    int control;
+    int add_crc;
+    uint32_t crc;
+    int packetnum;
+    uint8_t *p;
+
+    if ((s->tcr & TCR_TXEN) == 0)
+        return;
+    if (s->tx_fifo_len == 0)
+        return;
+    for (i = 0; i < s->tx_fifo_len; i++) {
+        packetnum = s->tx_fifo[i];
+        p = &s->data[packetnum][0];
+        /* Set status word.  */
+        *(p++) = 0x01;
+        *(p++) = 0x40;
+        len = *(p++);
+        len |= ((int)*(p++)) << 8;
+        len -= 6;
+        control = p[len + 1];
+        if (control & 0x20)
+            len++;
+        /* ??? This overwrites the data following the buffer.
+           Don't know what real hardware does.  */
+        if (len < 64 && (s->tcr & TCR_PAD_EN)) {
+            memset(p + len, 0, 64 - len);
+            len = 64;
+        }
+#if 0
+        /* The card is supposed to append the CRC to the frame.  However
+           none of the other network traffic has the CRC appended.
+           Suspect this is low level ethernet detail we don't need to worry
+           about.  */
+        add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
+        if (add_crc) {
+            crc = crc32(~0, p, len);
+            memcpy(p + len, &crc, 4);
+            len += 4;
+        }
+#else
+        add_crc = 0;
+#endif
+        if (s->ctr & CTR_AUTO_RELEASE)
+            /* Race?  */
+            smc91c111_release_packet(s, packetnum);
+        else if (s->tx_fifo_done_len < NUM_PACKETS)
+            s->tx_fifo_done[s->tx_fifo_done_len++] = packetnum;
+        qemu_send_packet(s->vc, p, len);
+    }
+    s->tx_fifo_len = 0;
+    smc91c111_update(s);
+}
+
+/* Add a packet to the TX FIFO.  */
+static void smc91c111_queue_tx(smc91c111_state *s, int packet)
+{
+    if (s->tx_fifo_len == NUM_PACKETS)
+        return;
+    s->tx_fifo[s->tx_fifo_len++] = packet;
+    smc91c111_do_tx(s);
+}
+
+static void smc91c111_reset(smc91c111_state *s)
+{
+    s->bank = 0;
+    s->tx_fifo_len = 0;
+    s->tx_fifo_done_len = 0;
+    s->rx_fifo_len = 0;
+    s->allocated = 0;
+    s->packet_num = 0;
+    s->tx_alloc = 0;
+    s->tcr = 0;
+    s->rcr = 0;
+    s->cr = 0xa0b1;
+    s->ctr = 0x1210;
+    s->ptr = 0;
+    s->ercv = 0x1f;
+    s->int_level = INT_TX_EMPTY;
+    s->int_mask = 0;
+    smc91c111_update(s);
+}
+
+#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
+#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
+
+static void smc91c111_writeb(void *opaque, target_phys_addr_t offset,
+                             uint32_t value)
+{
+    smc91c111_state *s = (smc91c111_state *)opaque;
+
+    offset -= s->base;
+    if (offset == 14) {
+        s->bank = value;
+        return;
+    }
+    if (offset == 15)
+        return;
+    switch (s->bank) {
+    case 0:
+        switch (offset) {
+        case 0: /* TCR */
+            SET_LOW(tcr, value);
+            return;
+        case 1:
+            SET_HIGH(tcr, value);
+            return;
+        case 4: /* RCR */
+            SET_LOW(rcr, value);
+            return;
+        case 5:
+            SET_HIGH(rcr, value);
+            if (s->rcr & RCR_SOFT_RST)
+                smc91c111_reset(s);
+            return;
+        case 10: case 11: /* RPCR */
+            /* Ignored */
+            return;
+        }
+        break;
+
+    case 1:
+        switch (offset) {
+        case 0: /* CONFIG */
+            SET_LOW(cr, value);
+            return;
+        case 1:
+            SET_HIGH(cr,value);
+            return;
+        case 2: case 3: /* BASE */
+        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
+            /* Not implemented.  */
+            return;
+        case 10: /* Genral Purpose */
+            SET_LOW(gpr, value);
+            return;
+        case 11:
+            SET_HIGH(gpr, value);
+            return;
+        case 12: /* Control */
+            if (value & 1)
+                fprintf(stderr, "smc91c111:EEPROM store not implemented\n");
+            if (value & 2)
+                fprintf(stderr, "smc91c111:EEPROM reload not implemented\n");
+            value &= ~3;
+            SET_LOW(ctr, value);
+            return;
+        case 13:
+            SET_HIGH(ctr, value);
+            return;
+        }
+        break;
+
+    case 2:
+        switch (offset) {
+        case 0: /* MMU Command */
+            switch (value >> 5) {
+            case 0: /* no-op */
+                break;
+            case 1: /* Allocate for TX.  */
+                s->tx_alloc = 0x80;
+                s->int_level &= ~INT_ALLOC;
+                smc91c111_update(s);
+                smc91c111_tx_alloc(s);
+                break;
+            case 2: /* Reset MMU.  */
+                s->allocated = 0;
+                s->tx_fifo_len = 0;
+                s->tx_fifo_done_len = 0;
+                s->rx_fifo_len = 0;
+                s->tx_alloc = 0;
+                break;
+            case 3: /* Remove from RX FIFO.  */
+                smc91c111_pop_rx_fifo(s);
+                break;
+            case 4: /* Remove from RX FIFO and release.  */
+                if (s->rx_fifo_len > 0) {
+                    smc91c111_release_packet(s, s->rx_fifo[0]);
+                }
+                smc91c111_pop_rx_fifo(s);
+                break;
+            case 5: /* Release.  */
+                smc91c111_release_packet(s, s->packet_num);
+                break;
+            case 6: /* Add to TX FIFO.  */
+                smc91c111_queue_tx(s, s->packet_num);
+                break;
+            case 7: /* Reset TX FIFO.  */
+                s->tx_fifo_len = 0;
+                s->tx_fifo_done_len = 0;
+                break;
+            }
+            return;
+        case 1:
+            /* Ignore.  */
+            return;
+        case 2: /* Packet Number Register */
+            s->packet_num = value;
+            return;
+        case 3: case 4: case 5:
+            /* Should be readonly, but linux writes to them anyway. Ignore.  */
+            return;
+        case 6: /* Pointer */
+            SET_LOW(ptr, value);
+            return;
+        case 7:
+            SET_HIGH(ptr, value);
+            return;
+        case 8: case 9: case 10: case 11: /* Data */
+            {
+                int p;
+                int n;
+
+                if (s->ptr & 0x8000)
+                    n = s->rx_fifo[0];
+                else
+                    n = s->packet_num;
+                p = s->ptr & 0x07ff;
+                if (s->ptr & 0x4000) {
+                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
+                } else {
+                    p += (offset & 3);
+                }
+                s->data[n][p] = value;
+            }
+            return;
+        case 12: /* Interrupt ACK.  */
+            s->int_level &= ~(value & 0xd6);
+            if (value & INT_TX)
+                smc91c111_pop_tx_fifo_done(s);
+            smc91c111_update(s);
+            return;
+        case 13: /* Interrupt mask.  */
+            s->int_mask = value;
+            smc91c111_update(s);
+            return;
+        }
+        break;;
+
+    case 3:
+        switch (offset) {
+        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+            /* Multicast table.  */
+            /* Not implemented.  */
+            return;
+        case 8: case 9: /* Management Interface.  */
+            /* Not implemented.  */
+            return;
+        case 12: /* Early receive.  */
+            s->ercv = value & 0x1f;
+        case 13:
+            /* Ignore.  */
+            return;
+        }
+        break;
+    }
+    cpu_abort (cpu_single_env, "smc91c111_write: Bad reg %d:%x\n",
+               s->bank, offset);
+}
+
+static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset)
+{
+    smc91c111_state *s = (smc91c111_state *)opaque;
+
+    offset -= s->base;
+    if (offset == 14) {
+        return s->bank;
+    }
+    if (offset == 15)
+        return 0x33;
+    switch (s->bank) {
+    case 0:
+        switch (offset) {
+        case 0: /* TCR */
+            return s->tcr & 0xff;
+        case 1:
+            return s->tcr >> 8;
+        case 2: /* EPH Status */
+            return 0;
+        case 3:
+            return 0x40;
+        case 4: /* RCR */
+            return s->rcr & 0xff;
+        case 5:
+            return s->rcr >> 8;
+        case 6: /* Counter */
+        case 7:
+            /* Not implemented.  */
+            return 0;
+        case 8: /* Free memory available.  */
+            {
+                int i;
+                int n;
+                n = 0;
+                for (i = 0; i < NUM_PACKETS; i++) {
+                    if (s->allocated & (1 << i))
+                        n++;
+                }
+                return n;
+            }
+        case 9: /* Memory size.  */
+            return NUM_PACKETS;
+        case 10: case 11: /* RPCR */
+            /* Not implemented.  */
+            return 0;
+        }
+        break;
+
+    case 1:
+        switch (offset) {
+        case 0: /* CONFIG */
+            return s->cr & 0xff;
+        case 1:
+            return s->cr >> 8;
+        case 2: case 3: /* BASE */
+            /* Not implemented.  */
+            return 0;
+        case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
+            return s->macaddr[offset - 4];
+        case 10: /* General Purpose */
+            return s->gpr & 0xff;
+        case 11:
+            return s->gpr >> 8;
+        case 12: /* Control */
+            return s->ctr & 0xff;
+        case 13:
+            return s->ctr >> 8;
+        }
+        break;
+
+    case 2:
+        switch (offset) {
+        case 0: case 1: /* MMUCR Busy bit.  */
+            return 0;
+        case 2: /* Packet Number.  */
+            return s->packet_num;
+        case 3: /* Allocation Result.  */
+            return s->tx_alloc;
+        case 4: /* TX FIFO */
+            if (s->tx_fifo_done_len == 0)
+                return 0x80;
+            else
+                return s->tx_fifo_done[0];
+        case 5: /* RX FIFO */
+            if (s->rx_fifo_len == 0)
+                return 0x80;
+            else
+                return s->rx_fifo[0];
+        case 6: /* Pointer */
+            return s->ptr & 0xff;
+        case 7:
+            return (s->ptr >> 8) & 0xf7;
+        case 8: case 9: case 10: case 11: /* Data */
+            {
+                int p;
+                int n;
+
+                if (s->ptr & 0x8000)
+                    n = s->rx_fifo[0];
+                else
+                    n = s->packet_num;
+                p = s->ptr & 0x07ff;
+                if (s->ptr & 0x4000) {
+                    s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
+                } else {
+                    p += (offset & 3);
+                }
+                return s->data[n][p];
+            }
+        case 12: /* Interrupt status.  */
+            return s->int_level;
+        case 13: /* Interrupt mask.  */
+            return s->int_mask;
+        }
+        break;
+
+    case 3:
+        switch (offset) {
+        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+            /* Multicast table.  */
+            /* Not implemented.  */
+            return 0;
+        case 8: /* Management Interface.  */
+            /* Not implemented.  */
+            return 0x30;
+        case 9:
+            return 0x33;
+        case 10: /* Revision.  */
+            return 0x91;
+        case 11:
+            return 0x33;
+        case 12:
+            return s->ercv;
+        case 13:
+            return 0;
+        }
+        break;
+    }
+    cpu_abort (cpu_single_env, "smc91c111_read: Bad reg %d:%x\n",
+               s->bank, offset);
+    return 0;
+}
+
+static void smc91c111_writew(void *opaque, target_phys_addr_t offset,
+                             uint32_t value)
+{
+    smc91c111_writeb(opaque, offset, value & 0xff);
+    smc91c111_writeb(opaque, offset + 1, value >> 8);
+}
+
+static void smc91c111_writel(void *opaque, target_phys_addr_t offset,
+                             uint32_t value)
+{
+    smc91c111_state *s = (smc91c111_state *)opaque;
+    /* 32-bit writes to offset 0xc only actually write to the bank select
+       register (offset 0xe)  */
+    if (offset != s->base + 0xc)
+        smc91c111_writew(opaque, offset, value & 0xffff);
+    smc91c111_writew(opaque, offset + 2, value >> 16);
+}
+
+static uint32_t smc91c111_readw(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t val;
+    val = smc91c111_readb(opaque, offset);
+    val |= smc91c111_readb(opaque, offset + 1) << 8;
+    return val;
+}
+
+static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t val;
+    val = smc91c111_readw(opaque, offset);
+    val |= smc91c111_readw(opaque, offset + 2) << 16;
+    return val;
+}
+
+static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
+{
+    smc91c111_state *s = (smc91c111_state *)opaque;
+    int status;
+    int packetsize;
+    uint32_t crc;
+    int packetnum;
+    uint8_t *p;
+
+    if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
+        return;
+    /* Short packets are padded with zeros.  Recieveing a packet
+       < 64 bytes long is considered an error condition.  */
+    if (size < 64)
+        packetsize = 64;
+    else
+        packetsize = (size & ~1);
+    packetsize += 6;
+    crc = (s->rcr & RCR_STRIP_CRC) == 0;
+    if (crc)
+        packetsize += 4;
+    /* TODO: Flag overrun and receive errors.  */
+    if (packetsize > 2048)
+        return;
+    packetnum = smc91c111_allocate_packet(s);
+    if (packetnum == 0x80)
+        return;
+    s->rx_fifo[s->rx_fifo_len++] = packetnum;
+
+    p = &s->data[packetnum][0];
+    /* ??? Multicast packets?  */
+    status = 0;
+    if (size > 1518)
+        status |= RS_TOOLONG;
+    if (size & 1)
+        status |= RS_ODDFRAME;
+    *(p++) = status & 0xff;
+    *(p++) = status >> 8;
+    *(p++) = packetsize & 0xff;
+    *(p++) = packetsize >> 8;
+    memcpy(p, buf, size & ~1);
+    p += (size & ~1);
+    /* Pad short packets.  */
+    if (size < 64) {
+        int pad;
+        
+        if (size & 1)
+            *(p++) = buf[size - 1];
+        pad = 64 - size;
+        memset(p, 0, pad);
+        p += pad;
+        size = 64;
+    }
+    /* It's not clear if the CRC should go before or after the last byte in
+       odd sized packets.  Linux disables the CRC, so that's no help.
+       The pictures in the documentation show the CRC aligned on a 16-bit
+       boundary before the last odd byte, so that's what we do.  */
+    if (crc) {
+        crc = crc32(~0, buf, size);
+        *(p++) = crc & 0xff; crc >>= 8;
+        *(p++) = crc & 0xff; crc >>= 8;
+        *(p++) = crc & 0xff; crc >>= 8;
+        *(p++) = crc & 0xff; crc >>= 8;
+    }
+    if (size & 1) {
+        *(p++) = buf[size - 1];
+        *(p++) = 0x60;
+    } else {
+        *(p++) = 0;
+        *(p++) = 0x40;
+    }
+    /* TODO: Raise early RX interrupt?  */
+    s->int_level |= INT_RCV;
+    smc91c111_update(s);
+}
+
+static CPUReadMemoryFunc *smc91c111_readfn[] = {
+    smc91c111_readb,
+    smc91c111_readw,
+    smc91c111_readl
+};
+
+static CPUWriteMemoryFunc *smc91c111_writefn[] = {
+    smc91c111_writeb,
+    smc91c111_writew,
+    smc91c111_writel
+};
+
+void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq)
+{
+    smc91c111_state *s;
+    int iomemtype;
+
+    s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state));
+    iomemtype = cpu_register_io_memory(0, smc91c111_readfn,
+                                       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);
+
+    smc91c111_reset(s);
+
+    s->vc = qemu_new_vlan_client(nd->vlan, smc91c111_receive, s);
+    /* ??? Save/restore.  */
+}
index 56b9069..5733fce 100644 (file)
@@ -22,7 +22,6 @@
  * THE SOFTWARE.
  */
 #include "vl.h"
-#include "m48t08.h"
 
 #define KERNEL_LOAD_ADDR     0x00004000
 #define CMDLINE_ADDR         0x007ff000
@@ -57,6 +56,7 @@
 #define PHYS_JJ_FDC    0x71400000      /* Floppy */
 #define PHYS_JJ_FLOPPY_IRQ 22
 #define PHYS_JJ_ME_IRQ 30              /* Module error, power fail */
+#define MAX_CPUS 16
 
 /* TSC handling */
 
@@ -88,36 +88,36 @@ void DMA_register_channel (int nchan,
 {
 }
 
-static void nvram_set_word (m48t08_t *nvram, uint32_t addr, uint16_t value)
+static void nvram_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
 {
-    m48t08_write(nvram, addr++, (value >> 8) & 0xff);
-    m48t08_write(nvram, addr++, value & 0xff);
+    m48t59_write(nvram, addr++, (value >> 8) & 0xff);
+    m48t59_write(nvram, addr++, value & 0xff);
 }
 
-static void nvram_set_lword (m48t08_t *nvram, uint32_t addr, uint32_t value)
+static void nvram_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
 {
-    m48t08_write(nvram, addr++, value >> 24);
-    m48t08_write(nvram, addr++, (value >> 16) & 0xff);
-    m48t08_write(nvram, addr++, (value >> 8) & 0xff);
-    m48t08_write(nvram, addr++, value & 0xff);
+    m48t59_write(nvram, addr++, value >> 24);
+    m48t59_write(nvram, addr++, (value >> 16) & 0xff);
+    m48t59_write(nvram, addr++, (value >> 8) & 0xff);
+    m48t59_write(nvram, addr++, value & 0xff);
 }
 
-static void nvram_set_string (m48t08_t *nvram, uint32_t addr,
+static void nvram_set_string (m48t59_t *nvram, uint32_t addr,
                        const unsigned char *str, uint32_t max)
 {
     unsigned int i;
 
     for (i = 0; i < max && str[i] != '\0'; i++) {
-        m48t08_write(nvram, addr + i, str[i]);
+        m48t59_write(nvram, addr + i, str[i]);
     }
-    m48t08_write(nvram, addr + max - 1, '\0');
+    m48t59_write(nvram, addr + max - 1, '\0');
 }
 
-static m48t08_t *nvram;
+static m48t59_t *nvram;
 
 extern int nographic;
 
-static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline,
+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)
@@ -129,9 +129,11 @@ static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline,
     nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16);
     nvram_set_lword(nvram,  0x10, 0x00000001); /* structure v1 */
     // NVRAM_size, arch not applicable
-    m48t08_write(nvram, 0x2F, nographic & 0xff);
+    m48t59_write(nvram, 0x2D, smp_cpus & 0xff);
+    m48t59_write(nvram, 0x2E, 0);
+    m48t59_write(nvram, 0x2F, nographic & 0xff);
     nvram_set_lword(nvram,  0x30, RAM_size);
-    m48t08_write(nvram, 0x34, boot_device & 0xff);
+    m48t59_write(nvram, 0x34, boot_device & 0xff);
     nvram_set_lword(nvram,  0x38, KERNEL_LOAD_ADDR);
     nvram_set_lword(nvram,  0x3C, kernel_size);
     if (cmdline) {
@@ -146,21 +148,21 @@ static void nvram_init(m48t08_t *nvram, uint8_t *macaddr, const char *cmdline,
 
     // Sun4m specific use
     i = 0x1fd8;
-    m48t08_write(nvram, i++, 0x01);
-    m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */
+    m48t59_write(nvram, i++, 0x01);
+    m48t59_write(nvram, i++, 0x80); /* Sun4m OBP */
     j = 0;
-    m48t08_write(nvram, i++, macaddr[j++]);
-    m48t08_write(nvram, i++, macaddr[j++]);
-    m48t08_write(nvram, i++, macaddr[j++]);
-    m48t08_write(nvram, i++, macaddr[j++]);
-    m48t08_write(nvram, i++, macaddr[j++]);
-    m48t08_write(nvram, i, macaddr[j]);
+    m48t59_write(nvram, i++, macaddr[j++]);
+    m48t59_write(nvram, i++, macaddr[j++]);
+    m48t59_write(nvram, i++, macaddr[j++]);
+    m48t59_write(nvram, i++, macaddr[j++]);
+    m48t59_write(nvram, i++, macaddr[j++]);
+    m48t59_write(nvram, i, macaddr[j]);
 
     /* Calculate checksum */
     for (i = 0x1fd8; i < 0x1fe7; i++) {
-       tmp ^= m48t08_read(nvram, i);
+       tmp ^= m48t59_read(nvram, i);
     }
-    m48t08_write(nvram, 0x1fe7, tmp);
+    m48t59_write(nvram, 0x1fe7, tmp);
 }
 
 static void *slavio_intctl;
@@ -180,6 +182,11 @@ void pic_set_irq(int irq, int level)
     slavio_pic_set_irq(slavio_intctl, irq, level);
 }
 
+void pic_set_irq_cpu(int irq, int level, unsigned int cpu)
+{
+    slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu);
+}
+
 static void *tcx;
 
 void vga_update_display()
@@ -211,12 +218,19 @@ void qemu_system_powerdown(void)
     slavio_set_power_fail(slavio_misc, 1);
 }
 
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    cpu_reset(env);
+}
+
 /* 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)
 {
+    CPUState *env, *envs[MAX_CPUS];
     char buf[1024];
     int ret, linux_boot;
     unsigned int i;
@@ -224,15 +238,31 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
 
     linux_boot = (kernel_filename != NULL);
 
+    /* init CPUs */
+    for(i = 0; i < smp_cpus; i++) {
+        env = cpu_init();
+        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]);
+    }
+
     tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height);
     lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA);
-    nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE);
-    slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ);
+    nvram = m48t59_init(0, PHYS_JJ_EEPROM, 0, PHYS_JJ_EEPROM_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(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 TTYA (base+4, Linux ttyS0) is the first Qemu serial device
     // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
index 9c89453..571e2b3 100644 (file)
@@ -68,60 +68,46 @@ void DMA_register_channel (int nchan,
 /* NVRAM helpers */
 void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
 {
-    m48t59_set_addr(nvram, addr);
-    m48t59_write(nvram, value);
+    m48t59_write(nvram, addr, value);
 }
 
 uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
 {
-    m48t59_set_addr(nvram, addr);
-    return m48t59_read(nvram);
+    return m48t59_read(nvram, addr);
 }
 
 void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
 {
-    m48t59_set_addr(nvram, addr);
-    m48t59_write(nvram, value >> 8);
-    m48t59_set_addr(nvram, addr + 1);
-    m48t59_write(nvram, value & 0xFF);
+    m48t59_write(nvram, addr, value >> 8);
+    m48t59_write(nvram, addr + 1, value & 0xFF);
 }
 
 uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
 {
     uint16_t tmp;
 
-    m48t59_set_addr(nvram, addr);
-    tmp = m48t59_read(nvram) << 8;
-    m48t59_set_addr(nvram, addr + 1);
-    tmp |= m48t59_read(nvram);
+    tmp = m48t59_read(nvram, addr) << 8;
+    tmp |= m48t59_read(nvram, addr + 1);
 
     return tmp;
 }
 
 void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
 {
-    m48t59_set_addr(nvram, addr);
-    m48t59_write(nvram, value >> 24);
-    m48t59_set_addr(nvram, addr + 1);
-    m48t59_write(nvram, (value >> 16) & 0xFF);
-    m48t59_set_addr(nvram, addr + 2);
-    m48t59_write(nvram, (value >> 8) & 0xFF);
-    m48t59_set_addr(nvram, addr + 3);
-    m48t59_write(nvram, value & 0xFF);
+    m48t59_write(nvram, addr, value >> 24);
+    m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF);
+    m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF);
+    m48t59_write(nvram, addr + 3, value & 0xFF);
 }
 
 uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
 {
     uint32_t tmp;
 
-    m48t59_set_addr(nvram, addr);
-    tmp = m48t59_read(nvram) << 24;
-    m48t59_set_addr(nvram, addr + 1);
-    tmp |= m48t59_read(nvram) << 16;
-    m48t59_set_addr(nvram, addr + 2);
-    tmp |= m48t59_read(nvram) << 8;
-    m48t59_set_addr(nvram, addr + 3);
-    tmp |= m48t59_read(nvram);
+    tmp = m48t59_read(nvram, addr) << 24;
+    tmp |= m48t59_read(nvram, addr + 1) << 16;
+    tmp |= m48t59_read(nvram, addr + 2) << 8;
+    tmp |= m48t59_read(nvram, addr + 3);
 
     return tmp;
 }
@@ -132,11 +118,9 @@ void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
     int i;
 
     for (i = 0; i < max && str[i] != '\0'; i++) {
-        m48t59_set_addr(nvram, addr + i);
-        m48t59_write(nvram, str[i]);
+        m48t59_write(nvram, addr + i, str[i]);
     }
-    m48t59_set_addr(nvram, addr + max - 1);
-    m48t59_write(nvram, '\0');
+    m48t59_write(nvram, addr + max - 1, '\0');
 }
 
 int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
@@ -251,6 +235,12 @@ void qemu_system_powerdown(void)
 {
 }
 
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    cpu_reset(env);
+}
+
 static const int ide_iobase[2] = { 0x1f0, 0x170 };
 static const int ide_iobase2[2] = { 0x3f6, 0x376 };
 static const int ide_irq[2] = { 14, 15 };
@@ -269,6 +259,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device,
              const char *kernel_filename, const char *kernel_cmdline,
              const char *initrd_filename)
 {
+    CPUState *env;
     char buf[1024];
     m48t59_t *nvram;
     int ret, linux_boot;
@@ -278,6 +269,10 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device,
 
     linux_boot = (kernel_filename != NULL);
 
+    env = cpu_init();
+    register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
+    qemu_register_reset(main_cpu_reset, env);
+
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, 0);
 
@@ -340,7 +335,8 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device,
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
-            serial_init(serial_io[i], serial_irq[i], serial_hds[i]);
+            serial_init(&pic_set_irq_new, NULL,
+                        serial_io[i], serial_irq[i], serial_hds[i]);
         }
     }
 
@@ -357,7 +353,7 @@ static void sun4u_init(int ram_size, int vga_ram_size, int boot_device,
     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);
+    nvram = m48t59_init(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/qemu/hw/usb-hid.c b/qemu/hw/usb-hid.c
new file mode 100644 (file)
index 0000000..6f9ee82
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * QEMU USB HID devices
+ * 
+ * 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"
+
+/* HID interface requests */
+#define GET_REPORT   0xa101
+#define GET_IDLE     0xa102
+#define GET_PROTOCOL 0xa103
+#define SET_IDLE     0x210a
+#define SET_PROTOCOL 0x210b
+
+typedef struct USBMouseState {
+    USBDevice dev;
+    int dx, dy, dz, buttons_state;
+} USBMouseState;
+
+/* 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,       /*  u8  bDeviceClass; */
+       0x00,       /*  u8  bDeviceSubClass; */
+       0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
+       0x08,       /*  u8  bMaxPacketSize0; 8 Bytes */
+
+       0x27, 0x06, /*  u16 idVendor; */
+       0x01, 0x00, /*  u16 idProduct; */
+       0x00, 0x00, /*  u16 bcdDevice */
+
+       0x03,       /*  u8  iManufacturer; */
+       0x02,       /*  u8  iProduct; */
+       0x01,       /*  u8  iSerialNumber; */
+       0x01        /*  u8  bNumConfigurations; */
+};
+
+static const uint8_t qemu_mouse_config_descriptor[] = {
+       /* one configuration */
+       0x09,       /*  u8  bLength; */
+       0x02,       /*  u8  bDescriptorType; Configuration */
+       0x22, 0x00, /*  u16 wTotalLength; */
+       0x01,       /*  u8  bNumInterfaces; (1) */
+       0x01,       /*  u8  bConfigurationValue; */
+       0x04,       /*  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
+        *
+        * 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; */
+       0x04,       /*  u8  if_bDescriptorType; Interface */
+       0x00,       /*  u8  if_bInterfaceNumber; */
+       0x00,       /*  u8  if_bAlternateSetting; */
+       0x01,       /*  u8  if_bNumEndpoints; */
+       0x03,       /*  u8  if_bInterfaceClass; */
+       0x01,       /*  u8  if_bInterfaceSubClass; */
+       0x02,       /*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
+       0x05,       /*  u8  if_iInterface; */
+     
+       /* 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 */
+       0x03, 0x00, /*  u16 ep_wMaxPacketSize; */
+       0x0a,       /*  u8  ep_bInterval; (255ms -- usb 2.0 spec) */
+
+        /* HID descriptor */
+        0x09,        /*  u8  bLength; */
+        0x21,        /*  u8 bDescriptorType; */
+        0x01, 0x00,  /*  u16 HID_class */
+        0x00,        /*  u8 country_code */
+        0x01,        /*  u8 num_descriptors */
+        0x22,        /*  u8 type; Report */
+        50, 0,       /*  u16 len */
+};
+
+static const uint8_t qemu_mouse_hid_report_descriptor[] = {
+    0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 
+    0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
+    0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 
+    0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
+    0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81, 
+    0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06,
+    0xC0, 0xC0,
+};
+
+static void usb_mouse_event(void *opaque,
+                            int dx1, int dy1, int dz1, int buttons_state)
+{
+    USBMouseState *s = opaque;
+
+    s->dx += dx1;
+    s->dy += dy1;
+    s->dz += dz1;
+    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(USBMouseState *s, uint8_t *buf, int len)
+{
+    int dx, dy, dz, b, l;
+
+    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 void usb_mouse_handle_reset(USBDevice *dev)
+{
+    USBMouseState *s = (USBMouseState *)dev;
+
+    s->dx = 0;
+    s->dy = 0;
+    s->dz = 0;
+    s->buttons_state = 0;
+}
+
+static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
+                                  int index, int length, uint8_t *data)
+{
+    USBMouseState *s = (USBMouseState *)dev;
+    int ret;
+
+    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_mouse_dev_descriptor, 
+                   sizeof(qemu_mouse_dev_descriptor));
+            ret = sizeof(qemu_mouse_dev_descriptor);
+            break;
+        case USB_DT_CONFIG:
+            memcpy(data, qemu_mouse_config_descriptor, 
+                   sizeof(qemu_mouse_config_descriptor));
+            ret = sizeof(qemu_mouse_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:
+                /* product description */
+                ret = set_usb_string(data, "QEMU USB Mouse");
+                break;
+            case 3:
+                /* vendor description */
+                ret = set_usb_string(data, "QEMU " QEMU_VERSION);
+                break;
+            case 4:
+                ret = set_usb_string(data, "HID Mouse");
+                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;
+        /* hid specific requests */
+    case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
+        switch(value >> 8) {
+        case 0x22:
+            memcpy(data, qemu_mouse_hid_report_descriptor, 
+                   sizeof(qemu_mouse_hid_report_descriptor));
+            ret = sizeof(qemu_mouse_hid_report_descriptor);
+            break;
+        default:
+            goto fail;
+        }
+        break;
+    case GET_REPORT:
+        ret = usb_mouse_poll(s, data, length);
+        break;
+    case SET_IDLE:
+        ret = 0;
+        break;
+    default:
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static int usb_mouse_handle_data(USBDevice *dev, int pid, 
+                                 uint8_t devep, uint8_t *data, int len)
+{
+    USBMouseState *s = (USBMouseState *)dev;
+    int ret;
+
+    switch(pid) {
+    case USB_TOKEN_IN:
+        if (devep == 1) {
+            ret = usb_mouse_poll(s, data, len);
+        } else {
+            goto fail;
+        }
+        break;
+    case USB_TOKEN_OUT:
+    default:
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+USBDevice *usb_mouse_init(void)
+{
+    USBMouseState *s;
+
+    s = qemu_mallocz(sizeof(USBMouseState));
+    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;
+
+    qemu_add_mouse_event_handler(usb_mouse_event, s);
+    
+    return (USBDevice *)s;
+}
diff --git a/qemu/hw/usb-uhci.c b/qemu/hw/usb-uhci.c
new file mode 100644 (file)
index 0000000..732b76a
--- /dev/null
@@ -0,0 +1,671 @@
+/*
+ * 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
+ * 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 DEBUG
+//#define DEBUG_PACKET
+
+#define UHCI_CMD_GRESET   (1 << 2)
+#define UHCI_CMD_HCRESET  (1 << 1)
+#define UHCI_CMD_RS       (1 << 0)
+
+#define UHCI_STS_HCHALTED (1 << 5)
+#define UHCI_STS_HCPERR   (1 << 4)
+#define UHCI_STS_HSERR    (1 << 3)
+#define UHCI_STS_RD       (1 << 2)
+#define UHCI_STS_USBERR   (1 << 1)
+#define UHCI_STS_USBINT   (1 << 0)
+
+#define TD_CTRL_SPD     (1 << 29)
+#define TD_CTRL_ERROR_SHIFT  27
+#define TD_CTRL_IOS     (1 << 25)
+#define TD_CTRL_IOC     (1 << 24)
+#define TD_CTRL_ACTIVE  (1 << 23)
+#define TD_CTRL_STALL   (1 << 22)
+#define TD_CTRL_BABBLE  (1 << 20)
+#define TD_CTRL_NAK     (1 << 19)
+#define TD_CTRL_TIMEOUT (1 << 18)
+
+#define UHCI_PORT_RESET (1 << 9)
+#define UHCI_PORT_LSDA  (1 << 8)
+#define UHCI_PORT_ENC   (1 << 3)
+#define UHCI_PORT_EN    (1 << 2)
+#define UHCI_PORT_CSC   (1 << 1)
+#define UHCI_PORT_CCS   (1 << 0)
+
+#define FRAME_TIMER_FREQ 1000
+
+#define FRAME_MAX_LOOPS  100
+
+#define NB_PORTS 2
+
+typedef struct UHCIPort {
+    USBPort port;
+    uint16_t ctrl;
+} UHCIPort;
+
+typedef struct UHCIState {
+    PCIDevice dev;
+    uint16_t cmd; /* cmd register */
+    uint16_t status;
+    uint16_t intr; /* interrupt enable register */
+    uint16_t frnum; /* frame number */
+    uint32_t fl_base_addr; /* frame list base address */
+    uint8_t sof_timing;
+    uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */
+    QEMUTimer *frame_timer;
+    UHCIPort ports[NB_PORTS];
+} UHCIState;
+
+typedef struct UHCI_TD {
+    uint32_t link;
+    uint32_t ctrl; /* see TD_CTRL_xxx */
+    uint32_t token;
+    uint32_t buffer;
+} UHCI_TD;
+
+typedef struct UHCI_QH {
+    uint32_t link;
+    uint32_t el_link;
+} UHCI_QH;
+
+static void uhci_attach(USBPort *port1, USBDevice *dev);
+
+static void uhci_update_irq(UHCIState *s)
+{
+    int level;
+    if (((s->status2 & 1) && (s->intr & (1 << 2))) ||
+        ((s->status2 & 2) && (s->intr & (1 << 3))) ||
+        ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) ||
+        ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) ||
+        (s->status & UHCI_STS_HSERR) ||
+        (s->status & UHCI_STS_HCPERR)) {
+        level = 1;
+    } else {
+        level = 0;
+    }
+    pci_set_irq(&s->dev, 3, level);
+}
+
+static void uhci_reset(UHCIState *s)
+{
+    uint8_t *pci_conf;
+    int i;
+    UHCIPort *port;
+
+    pci_conf = s->dev.config;
+
+    pci_conf[0x6a] = 0x01; /* usb clock */
+    pci_conf[0x6b] = 0x00;
+    s->cmd = 0;
+    s->status = 0;
+    s->status2 = 0;
+    s->intr = 0;
+    s->fl_base_addr = 0;
+    s->sof_timing = 64;
+    for(i = 0; i < NB_PORTS; i++) {
+        port = &s->ports[i];
+        port->ctrl = 0x0080;
+        if (port->port.dev)
+            uhci_attach(&port->port, port->port.dev);
+    }
+}
+
+static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+    UHCIState *s = opaque;
+    
+    addr &= 0x1f;
+    switch(addr) {
+    case 0x0c:
+        s->sof_timing = val;
+        break;
+    }
+}
+
+static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr)
+{
+    UHCIState *s = opaque;
+    uint32_t val;
+
+    addr &= 0x1f;
+    switch(addr) {
+    case 0x0c:
+        val = s->sof_timing;
+    default:
+        val = 0xff;
+        break;
+    }
+    return val;
+}
+
+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);
+#endif
+    switch(addr) {
+    case 0x00:
+        if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
+            /* start frame processing */
+            qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock));
+        }
+        if (val & UHCI_CMD_GRESET) {
+            UHCIPort *port;
+            USBDevice *dev;
+            int i;
+
+            /* send reset on the USB bus */
+            for(i = 0; i < NB_PORTS; i++) {
+                port = &s->ports[i];
+                dev = port->port.dev;
+                if (dev) {
+                    dev->handle_packet(dev, 
+                                       USB_MSG_RESET, 0, 0, NULL, 0);
+                }
+            }
+            uhci_reset(s);
+            return;
+        }
+        if (val & UHCI_CMD_HCRESET) {
+            uhci_reset(s);
+            return;
+        }
+        s->cmd = val;
+        break;
+    case 0x02:
+        s->status &= ~val;
+        /* XXX: the chip spec is not coherent, so we add a hidden
+           register to distinguish between IOC and SPD */
+        if (val & UHCI_STS_USBINT)
+            s->status2 = 0;
+        uhci_update_irq(s);
+        break;
+    case 0x04:
+        s->intr = val;
+        uhci_update_irq(s);
+        break;
+    case 0x06:
+        if (s->status & UHCI_STS_HCHALTED)
+            s->frnum = val & 0x7ff;
+        break;
+    case 0x10 ... 0x1f:
+        {
+            UHCIPort *port;
+            USBDevice *dev;
+            int n;
+
+            n = (addr >> 1) & 7;
+            if (n >= NB_PORTS)
+                return;
+            port = &s->ports[n];
+            dev = port->port.dev;
+            if (dev) {
+                /* port reset */
+                if ( (val & UHCI_PORT_RESET) && 
+                     !(port->ctrl & UHCI_PORT_RESET) ) {
+                    dev->handle_packet(dev, 
+                                       USB_MSG_RESET, 0, 0, NULL, 0);
+                }
+            }
+            port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb);
+            /* some bits are reset when a '1' is written to them */
+            port->ctrl &= ~(val & 0x000a);
+        }
+        break;
+    }
+}
+
+static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr)
+{
+    UHCIState *s = opaque;
+    uint32_t val;
+
+    addr &= 0x1f;
+    switch(addr) {
+    case 0x00:
+        val = s->cmd;
+        break;
+    case 0x02:
+        val = s->status;
+        break;
+    case 0x04:
+        val = s->intr;
+        break;
+    case 0x06:
+        val = s->frnum;
+        break;
+    case 0x10 ... 0x1f:
+        {
+            UHCIPort *port;
+            int n;
+            n = (addr >> 1) & 7;
+            if (n >= NB_PORTS) 
+                goto read_default;
+            port = &s->ports[n];
+            val = port->ctrl;
+        }
+        break;
+    default:
+    read_default:
+        val = 0xff7f; /* disabled port */
+        break;
+    }
+#ifdef DEBUG
+    printf("uhci readw port=0x%04x val=0x%04x\n", addr, val);
+#endif
+    return val;
+}
+
+static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+    UHCIState *s = opaque;
+
+    addr &= 0x1f;
+#ifdef DEBUG
+    printf("uhci writel port=0x%04x val=0x%08x\n", addr, val);
+#endif
+    switch(addr) {
+    case 0x08:
+        s->fl_base_addr = val & ~0xfff;
+        break;
+    }
+}
+
+static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr)
+{
+    UHCIState *s = opaque;
+    uint32_t val;
+
+    addr &= 0x1f;
+    switch(addr) {
+    case 0x08:
+        val = s->fl_base_addr;
+        break;
+    default:
+        val = 0xffffffff;
+        break;
+    }
+    return val;
+}
+
+static void uhci_attach(USBPort *port1, USBDevice *dev)
+{
+    UHCIState *s = port1->opaque;
+    UHCIPort *port = &s->ports[port1->index];
+
+    if (dev) {
+        if (port->port.dev) {
+            usb_attach(port1, NULL);
+        }
+        /* set connect status */
+        if (!(port->ctrl & UHCI_PORT_CCS)) {
+            port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
+        }
+        /* update speed */
+        if (dev->speed == USB_SPEED_LOW)
+            port->ctrl |= UHCI_PORT_LSDA;
+        else
+            port->ctrl &= ~UHCI_PORT_LSDA;
+        port->port.dev = dev;
+        /* send the attach message */
+        dev->handle_packet(dev, 
+                           USB_MSG_ATTACH, 0, 0, NULL, 0);
+    } else {
+        /* set connect status */
+        if (!(port->ctrl & UHCI_PORT_CCS)) {
+            port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
+        }
+        /* disable port */
+        if (port->ctrl & UHCI_PORT_EN) {
+            port->ctrl &= ~UHCI_PORT_EN;
+            port->ctrl |= UHCI_PORT_ENC;
+        }
+        dev = port->port.dev;
+        if (dev) {
+            /* send the detach message */
+            dev->handle_packet(dev, 
+                               USB_MSG_DETACH, 0, 0, NULL, 0);
+        }
+        port->port.dev = NULL;
+    }
+}
+
+static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, 
+                                 uint8_t devaddr, uint8_t devep,
+                                 uint8_t *data, int len)
+{
+    UHCIPort *port;
+    USBDevice *dev;
+    int i, ret;
+
+#ifdef DEBUG_PACKET
+    {
+        const char *pidstr;
+        switch(pid) {
+        case USB_TOKEN_SETUP: pidstr = "SETUP"; break;
+        case USB_TOKEN_IN: pidstr = "IN"; break;
+        case USB_TOKEN_OUT: pidstr = "OUT"; break;
+        default: pidstr = "?"; break;
+        }
+        printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n",
+               s->frnum, pidstr, devaddr, devep, len);
+        if (pid != USB_TOKEN_IN) {
+            printf("     data_out=");
+            for(i = 0; i < len; i++) {
+                printf(" %02x", data[i]);
+            }
+            printf("\n");
+        }
+    }
+#endif
+    for(i = 0; i < NB_PORTS; i++) {
+        port = &s->ports[i];
+        dev = port->port.dev;
+        if (dev && (port->ctrl & UHCI_PORT_EN)) {
+            ret = dev->handle_packet(dev, pid, 
+                                     devaddr, devep,
+                                     data, len);
+            if (ret != USB_RET_NODEV) {
+#ifdef DEBUG_PACKET
+                {
+                    printf("     ret=%d ", ret);
+                    if (pid == USB_TOKEN_IN && ret > 0) {
+                        printf("data_in=");
+                        for(i = 0; i < ret; i++) {
+                            printf(" %02x", data[i]);
+                        }
+                    }
+                    printf("\n");
+                }
+#endif
+                return ret;
+            }
+        }
+    }
+    return USB_RET_NODEV;
+}
+
+/* return -1 if fatal error (frame must be stopped)
+          0 if TD successful
+          1 if TD unsuccessful or inactive
+*/
+static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask)
+{
+    uint8_t pid;
+    uint8_t buf[1280];
+    int len, max_len, err, ret;
+
+    if (td->ctrl & TD_CTRL_IOC) {
+        *int_mask |= 0x01;
+    }
+    
+    if (!(td->ctrl & TD_CTRL_ACTIVE))
+        return 1;
+
+    /* TD is active */
+    max_len = ((td->token >> 21) + 1) & 0x7ff;
+    pid = td->token & 0xff;
+    switch(pid) {
+    case USB_TOKEN_OUT:
+    case USB_TOKEN_SETUP:
+        cpu_physical_memory_read(td->buffer, buf, max_len);
+        ret = uhci_broadcast_packet(s, pid, 
+                                    (td->token >> 8) & 0x7f,
+                                    (td->token >> 15) & 0xf,
+                                    buf, max_len);
+        len = max_len;
+        break;
+    case USB_TOKEN_IN:
+        ret = uhci_broadcast_packet(s, pid, 
+                                    (td->token >> 8) & 0x7f,
+                                    (td->token >> 15) & 0xf,
+                                    buf, max_len);
+        if (ret >= 0) {
+            len = ret;
+            if (len > max_len) {
+                len = max_len;
+                ret = USB_RET_BABBLE;
+            }
+            if (len > 0) {
+                /* write the data back */
+                cpu_physical_memory_write(td->buffer, buf, len);
+            }
+        } else {
+            len = 0;
+        }
+        break;
+    default:
+        /* invalid pid : frame interrupted */
+        s->status |= UHCI_STS_HCPERR;
+        uhci_update_irq(s);
+        return -1;
+    }
+    if (td->ctrl & TD_CTRL_IOS)
+        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 && 
+            (td->ctrl & TD_CTRL_SPD) &&
+            len < max_len) {
+            *int_mask |= 0x02;
+            /* short packet: do not update QH */
+            return 1;
+        } else {
+            /* success */
+            return 0;
+        }
+    } else {
+        switch(ret) {
+        default:
+        case USB_RET_NODEV:
+        do_timeout:
+            td->ctrl |= TD_CTRL_TIMEOUT;
+            err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3;
+            if (err != 0) {
+                err--;
+                if (err == 0) {
+                    td->ctrl &= ~TD_CTRL_ACTIVE;
+                    s->status |= UHCI_STS_USBERR;
+                    uhci_update_irq(s);
+                }
+            }
+            td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | 
+                (err << TD_CTRL_ERROR_SHIFT);
+            return 1;
+        case USB_RET_NAK:
+            td->ctrl |= TD_CTRL_NAK;
+            if (pid == USB_TOKEN_SETUP)
+                goto do_timeout;
+            return 1;
+        case USB_RET_STALL:
+            td->ctrl |= TD_CTRL_STALL;
+            td->ctrl &= ~TD_CTRL_ACTIVE;
+            return 1;
+        case USB_RET_BABBLE:
+            td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
+            td->ctrl &= ~TD_CTRL_ACTIVE;
+            /* frame interrupted */
+            return -1;
+        }
+    }
+}
+
+static void uhci_frame_timer(void *opaque)
+{
+    UHCIState *s = opaque;
+    int64_t expire_time;
+    uint32_t frame_addr, link, old_td_ctrl, val;
+    int int_mask, cnt, ret;
+    UHCI_TD td;
+    UHCI_QH qh;
+
+    if (!(s->cmd & UHCI_CMD_RS)) {
+        qemu_del_timer(s->frame_timer);
+        return;
+    }
+    frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2);
+    cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4);
+    le32_to_cpus(&link);
+    int_mask = 0;
+    cnt = FRAME_MAX_LOOPS;
+    while ((link & 1) == 0) {
+        if (--cnt == 0)
+            break;
+        /* valid frame */
+        if (link & 2) {
+            /* QH */
+            cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh));
+            le32_to_cpus(&qh.link);
+            le32_to_cpus(&qh.el_link);
+        depth_first:
+            if (qh.el_link & 1) {
+                /* no element : go to next entry */
+                link = qh.link;
+            } else if (qh.el_link & 2) {
+                /* QH */
+                link = qh.el_link;
+            } else {
+                /* TD */
+                if (--cnt == 0)
+                    break;
+                cpu_physical_memory_read(qh.el_link & ~0xf, 
+                                         (uint8_t *)&td, sizeof(td));
+                le32_to_cpus(&td.link);
+                le32_to_cpus(&td.ctrl);
+                le32_to_cpus(&td.token);
+                le32_to_cpus(&td.buffer);
+                old_td_ctrl = td.ctrl;
+                ret = uhci_handle_td(s, &td, &int_mask);
+                /* 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, 
+                                              sizeof(val));
+                }
+                if (ret < 0)
+                    break; /* interrupted frame */
+                if (ret == 0) {
+                    /* 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, 
+                                              sizeof(val));
+                    if (qh.el_link & 4) {
+                        /* depth first */
+                        goto depth_first;
+                    }
+                }
+                /* go to next entry */
+                link = qh.link;
+            }
+        } else {
+            /* TD */
+            cpu_physical_memory_read(link & ~0xf, (uint8_t *)&td, sizeof(td));
+            le32_to_cpus(&td.link);
+            le32_to_cpus(&td.ctrl);
+            le32_to_cpus(&td.token);
+            le32_to_cpus(&td.buffer);
+            old_td_ctrl = td.ctrl;
+            ret = uhci_handle_td(s, &td, &int_mask);
+            /* 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, 
+                                          sizeof(val));
+            }
+            if (ret < 0)
+                break; /* interrupted frame */
+            link = td.link;
+        }
+    }
+    s->frnum = (s->frnum + 1) & 0x7ff;
+    if (int_mask) {
+        s->status2 |= int_mask;
+        s->status |= UHCI_STS_USBINT;
+        uhci_update_irq(s);
+    }
+    /* prepare the timer for the next frame */
+    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, 
+                    uint32_t addr, uint32_t size, int type)
+{
+    UHCIState *s = (UHCIState *)pci_dev;
+
+    register_ioport_write(addr, 32, 2, uhci_ioport_writew, s);
+    register_ioport_read(addr, 32, 2, uhci_ioport_readw, s);
+    register_ioport_write(addr, 32, 4, uhci_ioport_writel, s);
+    register_ioport_read(addr, 32, 4, uhci_ioport_readl, s);
+    register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s);
+    register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
+}
+
+void usb_uhci_init(PCIBus *bus, USBPort **usb_ports)
+{
+    UHCIState *s;
+    uint8_t *pci_conf;
+    UHCIPort *port;
+    int i;
+
+    s = (UHCIState *)pci_register_device(bus,
+                                        "USB-UHCI", sizeof(UHCIState),
+                                        ((PCIDevice *)piix3_state)->devfn + 2, 
+                                        NULL, NULL);
+    pci_conf = s->dev.config;
+    pci_conf[0x00] = 0x86;
+    pci_conf[0x01] = 0x80;
+    pci_conf[0x02] = 0x20;
+    pci_conf[0x03] = 0x70;
+    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
+    
+    for(i = 0; i < NB_PORTS; i++) {
+        port = &s->ports[i];
+        port->port.opaque = s;
+        port->port.index = i;
+        port->port.attach = uhci_attach;
+        usb_ports[i] = &port->port;
+    }
+    s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
+
+    uhci_reset(s);
+
+    pci_register_io_region(&s->dev, 0, 0x20, 
+                           PCI_ADDRESS_SPACE_IO, uhci_map);
+}
diff --git a/qemu/hw/usb.c b/qemu/hw/usb.c
new file mode 100644 (file)
index 0000000..b2830c5
--- /dev/null
@@ -0,0 +1,690 @@
+/*
+ * 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
+ * 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"
+
+void usb_attach(USBPort *port, USBDevice *dev)
+{
+    port->attach(port, dev);
+}
+
+/**********************/
+/* generic USB device helpers (you are not forced to use them when
+   writing your USB device driver, but they help handling the
+   protocol) 
+*/
+
+#define SETUP_STATE_IDLE 0
+#define SETUP_STATE_DATA 1
+#define SETUP_STATE_ACK  2
+
+int usb_generic_handle_packet(USBDevice *s, int pid, 
+                              uint8_t devaddr, uint8_t devep,
+                              uint8_t *data, int len)
+{
+    int l, ret = 0;
+
+    switch(pid) {
+    case USB_MSG_ATTACH:
+        s->state = USB_STATE_ATTACHED;
+        break;
+    case USB_MSG_DETACH:
+        s->state = USB_STATE_NOTATTACHED;
+        break;
+    case USB_MSG_RESET:
+        s->remote_wakeup = 0;
+        s->addr = 0;
+        s->state = USB_STATE_DEFAULT;
+        s->handle_reset(s);
+        break;
+    case USB_TOKEN_SETUP:
+        if (s->state < USB_STATE_DEFAULT || devaddr != s->addr)
+            return USB_RET_NODEV;
+        if (len != 8)
+            goto fail;
+        memcpy(s->setup_buf, data, 8);
+        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, 
+                                    (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],
+                                    s->setup_len,
+                                    s->data_buf);
+            if (ret < 0)
+                return ret;
+            if (ret < s->setup_len)
+                s->setup_len = ret;
+            s->setup_state = SETUP_STATE_DATA;
+        } else {
+            if (s->setup_len == 0)
+                s->setup_state = SETUP_STATE_ACK;
+            else
+                s->setup_state = SETUP_STATE_DATA;
+        }
+        break;
+    case USB_TOKEN_IN:
+        if (s->state < USB_STATE_DEFAULT || devaddr != s->addr)
+            return USB_RET_NODEV;
+        switch(devep) {
+        case 0:
+            switch(s->setup_state) {
+            case SETUP_STATE_ACK:
+                s->setup_state = SETUP_STATE_IDLE;
+                if (!(s->setup_buf[0] & USB_DIR_IN)) {
+                    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],
+                                      s->setup_len,
+                                      s->data_buf);
+                    if (ret > 0)
+                        ret = 0;
+                } else {
+                    goto fail;
+                }
+                break;
+            case SETUP_STATE_DATA:
+                if (s->setup_buf[0] & USB_DIR_IN) {
+                    l = s->setup_len - s->setup_index;
+                    if (l > len)
+                        l = len;
+                    memcpy(data, s->data_buf + s->setup_index, l);
+                    s->setup_index += l;
+                    if (s->setup_index >= s->setup_len)
+                        s->setup_state = SETUP_STATE_ACK;
+                    ret = l;
+                } else {
+                    s->setup_state = SETUP_STATE_IDLE;
+                    goto fail;
+                }
+                break;
+            default:
+                goto fail;
+            }
+            break;
+        default:
+            ret = s->handle_data(s, pid, devep, data, len);
+            break;
+        }
+        break;
+    case USB_TOKEN_OUT:
+        if (s->state < USB_STATE_DEFAULT || devaddr != s->addr)
+            return USB_RET_NODEV;
+        switch(devep) {
+        case 0:
+            switch(s->setup_state) {
+            case SETUP_STATE_ACK:
+                s->setup_state = SETUP_STATE_IDLE;
+                if (s->setup_buf[0] & USB_DIR_IN) {
+                    /* transfer OK */
+                } else {
+                    goto fail;
+                }
+                break;
+            case SETUP_STATE_DATA:
+                if (!(s->setup_buf[0] & USB_DIR_IN)) {
+                    l = s->setup_len - s->setup_index;
+                    if (l > len)
+                        l = len;
+                    memcpy(s->data_buf + s->setup_index, data, l);
+                    s->setup_index += l;
+                    if (s->setup_index >= s->setup_len)
+                        s->setup_state = SETUP_STATE_ACK;
+                    ret = l;
+                } else {
+                    s->setup_state = SETUP_STATE_IDLE;
+                    goto fail;
+                }
+                break;
+            default:
+                goto fail;
+            }
+            break;
+        default:
+            ret = s->handle_data(s, pid, devep, data, len);
+            break;
+        }
+        break;
+    default:
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+/* XXX: fix overflow */
+int set_usb_string(uint8_t *buf, const char *str)
+{
+    int len, i;
+    uint8_t *q;
+
+    q = buf;
+    len = strlen(str);
+    *q++ = 2 * len + 1;
+    *q++ = 3;
+    for(i = 0; i < len; i++) {
+        *q++ = str[i];
+        *q++ = 0;
+    }
+    return q - buf;
+}
+
+/**********************/
+/* USB hub emulation */
+
+//#define DEBUG
+
+#define MAX_PORTS 8
+
+typedef struct USBHubPort {
+    USBPort port;
+    uint16_t wPortStatus;
+    uint16_t wPortChange;
+} USBHubPort;
+
+typedef struct USBHubState {
+    USBDevice dev;
+    int nb_ports;
+    USBHubPort ports[MAX_PORTS];
+} USBHubState;
+
+#define ClearHubFeature                (0x2000 | USB_REQ_CLEAR_FEATURE)
+#define ClearPortFeature       (0x2300 | USB_REQ_CLEAR_FEATURE)
+#define GetHubDescriptor       (0xa000 | USB_REQ_GET_DESCRIPTOR)
+#define GetHubStatus           (0xa000 | USB_REQ_GET_STATUS)
+#define GetPortStatus          (0xa300 | USB_REQ_GET_STATUS)
+#define SetHubFeature          (0x2000 | USB_REQ_SET_FEATURE)
+#define SetPortFeature         (0x2300 | USB_REQ_SET_FEATURE)
+
+#define PORT_STAT_CONNECTION   0x0001
+#define PORT_STAT_ENABLE       0x0002
+#define PORT_STAT_SUSPEND      0x0004
+#define PORT_STAT_OVERCURRENT  0x0008
+#define PORT_STAT_RESET                0x0010
+#define PORT_STAT_POWER                0x0100
+#define PORT_STAT_LOW_SPEED    0x0200
+#define PORT_STAT_HIGH_SPEED    0x0400
+#define PORT_STAT_TEST          0x0800
+#define PORT_STAT_INDICATOR     0x1000
+
+#define PORT_STAT_C_CONNECTION 0x0001
+#define PORT_STAT_C_ENABLE     0x0002
+#define PORT_STAT_C_SUSPEND    0x0004
+#define PORT_STAT_C_OVERCURRENT        0x0008
+#define PORT_STAT_C_RESET      0x0010
+
+#define PORT_CONNECTION                0
+#define PORT_ENABLE            1
+#define PORT_SUSPEND           2
+#define PORT_OVERCURRENT       3
+#define PORT_RESET             4
+#define PORT_POWER             8
+#define PORT_LOWSPEED          9
+#define PORT_HIGHSPEED         10
+#define PORT_C_CONNECTION      16
+#define PORT_C_ENABLE          17
+#define PORT_C_SUSPEND         18
+#define PORT_C_OVERCURRENT     19
+#define PORT_C_RESET           20
+#define PORT_TEST               21
+#define PORT_INDICATOR          22
+
+/* same as Linux kernel root hubs */
+
+static const uint8_t qemu_hub_dev_descriptor[] = {
+       0x12,       /*  u8 bLength; */
+       0x01,       /*  u8 bDescriptorType; Device */
+       0x10, 0x01, /*  u16 bcdUSB; v1.1 */
+
+       0x09,       /*  u8  bDeviceClass; HUB_CLASSCODE */
+       0x00,       /*  u8  bDeviceSubClass; */
+       0x00,       /*  u8  bDeviceProtocol; [ low/full speeds only ] */
+       0x08,       /*  u8  bMaxPacketSize0; 8 Bytes */
+
+       0x00, 0x00, /*  u16 idVendor; */
+       0x00, 0x00, /*  u16 idProduct; */
+       0x01, 0x01, /*  u16 bcdDevice */
+
+       0x03,       /*  u8  iManufacturer; */
+       0x02,       /*  u8  iProduct; */
+       0x01,       /*  u8  iSerialNumber; */
+       0x01        /*  u8  bNumConfigurations; */
+};
+
+/* XXX: patch interrupt size */
+static const uint8_t qemu_hub_config_descriptor[] = {
+
+       /* one configuration */
+       0x09,       /*  u8  bLength; */
+       0x02,       /*  u8  bDescriptorType; Configuration */
+       0x19, 0x00, /*  u16 wTotalLength; */
+       0x01,       /*  u8  bNumInterfaces; (1) */
+       0x01,       /*  u8  bConfigurationValue; */
+       0x00,       /*  u8  iConfiguration; */
+       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
+        *
+        * 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; */
+       0x04,       /*  u8  if_bDescriptorType; Interface */
+       0x00,       /*  u8  if_bInterfaceNumber; */
+       0x00,       /*  u8  if_bAlternateSetting; */
+       0x01,       /*  u8  if_bNumEndpoints; */
+       0x09,       /*  u8  if_bInterfaceClass; HUB_CLASSCODE */
+       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 */
+       0x81,       /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
+       0x03,       /*  u8  ep_bmAttributes; Interrupt */
+       0x02, 0x00, /*  u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
+       0xff        /*  u8  ep_bInterval; (255ms -- usb 2.0 spec) */
+};
+
+static const uint8_t qemu_hub_hub_descriptor[] =
+{
+       0x09,                   /*  u8  bLength; */
+       0x29,                   /*  u8  bDescriptorType; Hub-descriptor */
+       0x00,                   /*  u8  bNbrPorts; (patched later) */
+       0x0a,                   /* u16  wHubCharacteristics; */
+       0x00,                   /*   (per-port OC, no power switching) */
+       0x01,                   /*  u8  bPwrOn2pwrGood; 2ms */
+       0x00,                   /*  u8  bHubContrCurrent; 0 mA */
+       0x00,                   /*  u8  DeviceRemovable; *** 7 Ports max *** */
+       0xff                    /*  u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+static void usb_hub_attach(USBPort *port1, USBDevice *dev)
+{
+    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)
+            port->wPortStatus |= PORT_STAT_LOW_SPEED;
+        else
+            port->wPortStatus &= ~PORT_STAT_LOW_SPEED;
+        port->port.dev = dev;
+    } else {
+        dev = port->port.dev;
+        if (dev) {
+            port->wPortStatus &= ~PORT_STAT_CONNECTION;
+            port->wPortChange |= PORT_STAT_C_CONNECTION;
+            if (port->wPortStatus & PORT_STAT_ENABLE) {
+                port->wPortStatus &= ~PORT_STAT_ENABLE;
+                port->wPortChange |= PORT_STAT_C_ENABLE;
+            }
+            port->port.dev = NULL;
+        }
+    }
+}
+
+static void usb_hub_handle_reset(USBDevice *dev)
+{
+    /* XXX: do it */
+}
+
+static int usb_hub_handle_control(USBDevice *dev, int request, int value,
+                                  int index, int length, uint8_t *data)
+{
+    USBHubState *s = (USBHubState *)dev;
+    int ret;
+
+    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_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, 
+                   sizeof(qemu_hub_config_descriptor));
+            ret = sizeof(qemu_hub_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, "314159");
+                break;
+            case 2:
+                /* product description */
+                ret = set_usb_string(data, "QEMU USB Hub");
+                break;
+            case 3:
+                /* vendor description */
+                ret = set_usb_string(data, "QEMU " QEMU_VERSION);
+                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;
+        /* usb specific requests */
+    case GetHubStatus:
+        data[0] = 0;
+        data[1] = 0;
+        data[2] = 0;
+        data[3] = 0;
+        ret = 4;
+        break;
+    case GetPortStatus:
+        {
+            unsigned int n = index - 1;
+            USBHubPort *port;
+            if (n >= s->nb_ports)
+                goto fail;
+            port = &s->ports[n];
+            data[0] = port->wPortStatus;
+            data[1] = port->wPortStatus >> 8;
+            data[2] = port->wPortChange;
+            data[3] = port->wPortChange >> 8;
+            ret = 4;
+        }
+        break;
+    case SetHubFeature:
+    case ClearHubFeature:
+        if (value == 0 || value == 1) {
+        } else {
+            goto fail;
+        }
+        ret = 0;
+        break;
+    case SetPortFeature:
+        {
+            unsigned int n = index - 1;
+            USBHubPort *port;
+            USBDevice *dev;
+            if (n >= s->nb_ports)
+                goto fail;
+            port = &s->ports[n];
+            dev = port->port.dev;
+            switch(value) {
+            case PORT_SUSPEND:
+                port->wPortStatus |= PORT_STAT_SUSPEND;
+                break;
+            case PORT_RESET:
+                if (dev) {
+                    dev->handle_packet(dev, 
+                                       USB_MSG_RESET, 0, 0, NULL, 0);
+                    port->wPortChange |= PORT_STAT_C_RESET;
+                    /* set enable bit */
+                    port->wPortChange |= PORT_STAT_C_ENABLE;
+                    port->wPortStatus |= PORT_STAT_ENABLE;
+                }
+                break;
+            case PORT_POWER:
+                break;
+            default:
+                goto fail;
+            }
+            ret = 0;
+        }
+        break;
+    case ClearPortFeature:
+        {
+            unsigned int n = index - 1;
+            USBHubPort *port;
+            USBDevice *dev;
+            if (n >= s->nb_ports)
+                goto fail;
+            port = &s->ports[n];
+            dev = port->port.dev;
+            switch(value) {
+            case PORT_ENABLE:
+                port->wPortStatus &= ~PORT_STAT_ENABLE;
+                break;
+            case PORT_C_ENABLE:
+                port->wPortChange &= ~PORT_STAT_C_ENABLE;
+                break;
+            case PORT_SUSPEND:
+                port->wPortStatus &= ~PORT_STAT_SUSPEND;
+                break;
+            case PORT_C_SUSPEND:
+                port->wPortChange &= ~PORT_STAT_C_SUSPEND;
+                break;
+            case PORT_C_CONNECTION:
+                port->wPortChange &= ~PORT_STAT_C_CONNECTION;
+                break;
+            case PORT_C_OVERCURRENT:
+                port->wPortChange &= ~PORT_STAT_C_OVERCURRENT;
+                break;
+            case PORT_C_RESET:
+                port->wPortChange &= ~PORT_STAT_C_RESET;
+                break;
+            default:
+                goto fail;
+            }
+            ret = 0;
+        }
+        break;
+    case GetHubDescriptor:
+        memcpy(data, qemu_hub_hub_descriptor, 
+               sizeof(qemu_hub_hub_descriptor));
+        data[2] = s->nb_ports;
+        ret = sizeof(qemu_hub_hub_descriptor);
+        break;
+    default:
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static int usb_hub_handle_data(USBDevice *dev, int pid, 
+                               uint8_t devep, uint8_t *data, int len)
+{
+    USBHubState *s = (USBHubState *)dev;
+    int ret;
+
+    switch(pid) {
+    case USB_TOKEN_IN:
+        if (devep == 1) {
+            USBHubPort *port;
+            unsigned int status;
+            int i, n;
+            n = (s->nb_ports + 1 + 7) / 8;
+            if (n > len)
+                return USB_RET_BABBLE;
+            status = 0;
+            for(i = 0; i < s->nb_ports; i++) {
+                port = &s->ports[i];
+                if (port->wPortChange)
+                    status |= (1 << (i + 1));
+            }
+            if (status != 0) {
+                for(i = 0; i < n; i++) {
+                    data[i] = status >> (8 * i);
+                }
+                ret = n;
+            } else {
+                ret = 0;
+            }
+        } else {
+            goto fail;
+        }
+        break;
+    case USB_TOKEN_OUT:
+    default:
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static int usb_hub_broadcast_packet(USBHubState *s, int pid, 
+                                    uint8_t devaddr, uint8_t devep,
+                                    uint8_t *data, int len)
+{
+    USBHubPort *port;
+    USBDevice *dev;
+    int i, ret;
+
+    for(i = 0; i < s->nb_ports; i++) {
+        port = &s->ports[i];
+        dev = port->port.dev;
+        if (dev && (port->wPortStatus & PORT_STAT_ENABLE)) {
+            ret = dev->handle_packet(dev, pid, 
+                                     devaddr, devep,
+                                     data, len);
+            if (ret != USB_RET_NODEV) {
+                return ret;
+            }
+        }
+    }
+    return USB_RET_NODEV;
+}
+
+static int usb_hub_handle_packet(USBDevice *dev, int pid, 
+                                 uint8_t devaddr, uint8_t devep,
+                                 uint8_t *data, int len)
+{
+    USBHubState *s = (USBHubState *)dev;
+
+#if defined(DEBUG) && 0
+    printf("usb_hub: pid=0x%x\n", pid);
+#endif
+    if (dev->state == USB_STATE_DEFAULT &&
+        dev->addr != 0 &&
+        devaddr != dev->addr &&
+        (pid == USB_TOKEN_SETUP || 
+         pid == USB_TOKEN_OUT || 
+         pid == USB_TOKEN_IN)) {
+        /* broadcast the packet to the devices */
+        return usb_hub_broadcast_packet(s, pid, devaddr, devep, data, len);
+    }
+    return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len);
+}
+
+USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports)
+{
+    USBHubState *s;
+    USBHubPort *port;
+    int i;
+
+    if (nb_ports > MAX_PORTS)
+        return NULL;
+    s = qemu_mallocz(sizeof(USBHubState));
+    if (!s)
+        return NULL;
+    s->dev.speed = USB_SPEED_FULL;
+    s->dev.handle_packet = usb_hub_handle_packet;
+
+    /* generic USB device init */
+    s->dev.handle_reset = usb_hub_handle_reset;
+    s->dev.handle_control = usb_hub_handle_control;
+    s->dev.handle_data = usb_hub_handle_data;
+
+    s->nb_ports = nb_ports;
+    for(i = 0; i < s->nb_ports; i++) {
+        port = &s->ports[i];
+        port->wPortStatus = PORT_STAT_POWER;
+        port->wPortChange = 0;
+        port->port.attach = usb_hub_attach;
+        port->port.opaque = s;
+        port->port.index = i;
+        usb_ports[i] = &port->port;
+    }
+    return (USBDevice *)s;
+}
diff --git a/qemu/hw/usb.h b/qemu/hw/usb.h
new file mode 100644 (file)
index 0000000..b4dee23
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * 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
+ * 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.
+ */
+#define USB_TOKEN_SETUP 0x2d
+#define USB_TOKEN_IN    0x69 /* device -> host */
+#define USB_TOKEN_OUT   0xe1 /* host -> device */
+
+/* specific usb messages, also sent in the 'pid' parameter */
+#define USB_MSG_ATTACH   0x100
+#define USB_MSG_DETACH   0x101
+#define USB_MSG_RESET    0x102
+
+#define USB_RET_NODEV  (-1) 
+#define USB_RET_NAK    (-2)
+#define USB_RET_STALL  (-3)
+#define USB_RET_BABBLE (-4)
+
+#define USB_SPEED_LOW   0
+#define USB_SPEED_FULL  1
+#define USB_SPEED_HIGH  2
+
+#define USB_STATE_NOTATTACHED 0
+#define USB_STATE_ATTACHED    1
+//#define USB_STATE_POWERED     2
+#define USB_STATE_DEFAULT     3
+//#define USB_STATE_ADDRESS     4
+//#define      USB_STATE_CONFIGURED  5
+#define USB_STATE_SUSPENDED   6
+
+#define USB_CLASS_AUDIO                        1
+#define USB_CLASS_COMM                 2
+#define USB_CLASS_HID                  3
+#define USB_CLASS_PHYSICAL             5
+#define USB_CLASS_STILL_IMAGE          6
+#define USB_CLASS_PRINTER              7
+#define USB_CLASS_MASS_STORAGE         8
+#define USB_CLASS_HUB                  9
+#define USB_CLASS_CDC_DATA             0x0a
+#define USB_CLASS_CSCID                        0x0b
+#define USB_CLASS_CONTENT_SEC          0x0d
+#define USB_CLASS_APP_SPEC             0xfe
+#define USB_CLASS_VENDOR_SPEC          0xff
+
+#define USB_DIR_OUT                    0
+#define USB_DIR_IN                     0x80
+
+#define USB_TYPE_MASK                  (0x03 << 5)
+#define USB_TYPE_STANDARD              (0x00 << 5)
+#define USB_TYPE_CLASS                 (0x01 << 5)
+#define USB_TYPE_VENDOR                        (0x02 << 5)
+#define USB_TYPE_RESERVED              (0x03 << 5)
+
+#define USB_RECIP_MASK                 0x1f
+#define USB_RECIP_DEVICE               0x00
+#define USB_RECIP_INTERFACE            0x01
+#define USB_RECIP_ENDPOINT             0x02
+#define USB_RECIP_OTHER                        0x03
+
+#define DeviceRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
+#define DeviceOutRequest ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
+#define InterfaceRequest \
+        ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+#define InterfaceOutRequest \
+        ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+#define EndpointRequest ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
+#define EndpointOutRequest \
+        ((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT)<<8)
+
+#define USB_REQ_GET_STATUS             0x00
+#define USB_REQ_CLEAR_FEATURE          0x01
+#define USB_REQ_SET_FEATURE            0x03
+#define USB_REQ_SET_ADDRESS            0x05
+#define USB_REQ_GET_DESCRIPTOR         0x06
+#define USB_REQ_SET_DESCRIPTOR         0x07
+#define USB_REQ_GET_CONFIGURATION      0x08
+#define USB_REQ_SET_CONFIGURATION      0x09
+#define USB_REQ_GET_INTERFACE          0x0A
+#define USB_REQ_SET_INTERFACE          0x0B
+#define USB_REQ_SYNCH_FRAME            0x0C
+
+#define USB_DEVICE_SELF_POWERED                0
+#define USB_DEVICE_REMOTE_WAKEUP       1
+
+#define USB_DT_DEVICE                  0x01
+#define USB_DT_CONFIG                  0x02
+#define USB_DT_STRING                  0x03
+#define USB_DT_INTERFACE               0x04
+#define USB_DT_ENDPOINT                        0x05
+
+typedef struct USBPort USBPort;
+typedef struct USBDevice USBDevice;
+
+/* definition of a USB device */
+struct USBDevice {
+    void *opaque;
+    int (*handle_packet)(USBDevice *dev, int pid, 
+                         uint8_t devaddr, uint8_t devep,
+                         uint8_t *data, int len);
+    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. */
+    void (*handle_reset)(USBDevice *dev);
+    int (*handle_control)(USBDevice *dev, int request, int value,
+                          int index, int length, uint8_t *data);
+    int (*handle_data)(USBDevice *dev, int pid, uint8_t devep,
+                       uint8_t *data, int len);
+    uint8_t addr;
+    
+    int state;
+    uint8_t setup_buf[8];
+    uint8_t data_buf[1024];
+    int remote_wakeup;
+    int setup_state;
+    int setup_len;
+    int setup_index;
+};
+
+/* USB port on which a device can be connected */
+struct USBPort {
+    USBDevice *dev;
+    void (*attach)(USBPort *port, USBDevice *dev);
+    void *opaque;
+    int index; /* internal port index, may be used with the opaque */
+};
+
+void usb_attach(USBPort *port, USBDevice *dev);
+int usb_generic_handle_packet(USBDevice *s, int pid, 
+                              uint8_t devaddr, uint8_t devep,
+                              uint8_t *data, int len);
+int set_usb_string(uint8_t *buf, const char *str);
+
+/* usb hub */
+USBDevice *usb_hub_init(USBPort **usb_ports, int nb_ports);
+
+/* usb-uhci.c */
+void usb_uhci_init(PCIBus *bus, USBPort **usb_ports);
+
+/* usb-linux.c */
+USBDevice *usb_host_device_open(const char *devname);
+void usb_host_info(void);
+
+/* usb-hid.c */
+USBDevice *usb_mouse_init(void);
index 7b102c6..f1af656 100644 (file)
 
 #ifdef TARGET_I386
 
+#define ELF_PLATFORM get_elf_platform()
+
+static const char *get_elf_platform(void)
+{
+    static char elf_platform[] = "i386";
+    int family = (global_env->cpuid_version >> 8) & 0xff;
+    if (family > 6)
+        family = 6;
+    if (family >= 3)
+        elf_platform[1] = '0' + family;
+    return elf_platform;
+}
+
+#define ELF_HWCAP get_elf_hwcap()
+
+static uint32_t get_elf_hwcap(void)
+{
+  return global_env->cpuid_features;
+}
+
 #define ELF_START_MMAP 0x80000000
 
 /*
@@ -91,6 +111,22 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
 #define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      4096
 
+enum
+{
+  ARM_HWCAP_ARM_SWP       = 1 << 0,
+  ARM_HWCAP_ARM_HALF      = 1 << 1,
+  ARM_HWCAP_ARM_THUMB     = 1 << 2,
+  ARM_HWCAP_ARM_26BIT     = 1 << 3,
+  ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
+  ARM_HWCAP_ARM_FPA       = 1 << 5,
+  ARM_HWCAP_ARM_VFP       = 1 << 6,
+  ARM_HWCAP_ARM_EDSP      = 1 << 7,
+};
+
+#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF              \
+                    | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT     \
+                    | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
+
 #endif
 
 #ifdef TARGET_SPARC
@@ -211,6 +247,39 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info *
 
 #endif
 
+#ifdef TARGET_MIPS
+
+#define ELF_START_MMAP 0x80000000
+
+#define elf_check_arch(x) ( (x) == EM_MIPS )
+
+#define ELF_CLASS   ELFCLASS32
+#ifdef TARGET_WORDS_BIGENDIAN
+#define ELF_DATA       ELFDATA2MSB
+#else
+#define ELF_DATA       ELFDATA2LSB
+#endif
+#define ELF_ARCH    EM_MIPS
+
+#define ELF_PLAT_INIT(_r) 
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    regs->cp0_status = CP0St_UM;
+    regs->cp0_epc = infop->entry;
+    regs->regs[29] = infop->start_stack;
+}
+
+#endif /* TARGET_MIPS */
+
+#ifndef ELF_PLATFORM
+#define ELF_PLATFORM (NULL)
+#endif
+
+#ifndef ELF_HWCAP
+#define ELF_HWCAP 0
+#endif
+
 #include "elf.h"
 
 /*
@@ -292,7 +361,7 @@ struct exec
 #define INTERPRETER_AOUT 1
 #define INTERPRETER_ELF 2
 
-#define DLINFO_ITEMS 11
+#define DLINFO_ITEMS 12
 
 static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
 {
@@ -624,14 +693,26 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
 {
         target_ulong *argv, *envp;
         target_ulong *sp, *csp;
+        target_ulong *u_platform;
+        const char *k_platform;
         int v;
 
        /*
         * Force 16 byte _final_ alignment here for generality.
         */
         sp = (unsigned int *) (~15UL & (unsigned long) p);
+        u_platform = NULL;
+        k_platform = ELF_PLATFORM;
+        if (k_platform) {
+            size_t len = strlen(k_platform) + 1;
+            sp -= (len + sizeof(target_ulong) - 1) / sizeof(target_ulong);
+            u_platform = (target_ulong *)sp;
+            __copy_to_user(u_platform, k_platform, len);
+        }
         csp = sp;
         csp -= (DLINFO_ITEMS + 1) * 2;
+        if (k_platform)
+          csp -= 2;
 #ifdef DLINFO_ARCH_ITEMS
        csp -= DLINFO_ARCH_ITEMS*2;
 #endif
@@ -659,6 +740,9 @@ static unsigned int * create_elf_tables(char *p, int argc, int envc,
         NEW_AUX_ENT(AT_EUID, (target_ulong) geteuid());
         NEW_AUX_ENT(AT_GID, (target_ulong) getgid());
         NEW_AUX_ENT(AT_EGID, (target_ulong) getegid());
+        NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP);
+        if (k_platform)
+            NEW_AUX_ENT(AT_PLATFORM, (target_ulong) u_platform);
 #ifdef ARCH_DLINFO
        /* 
         * ARCH_DLINFO must come last so platform specific code can enforce
index 622d06e..ef3a171 100644 (file)
@@ -331,6 +331,7 @@ void cpu_loop(CPUARMState *env)
     int trapnr;
     unsigned int n, insn;
     target_siginfo_t info;
+    uint32_t addr;
     
     for(;;) {
         trapnr = cpu_arm_exec(env);
@@ -397,13 +398,18 @@ void cpu_loop(CPUARMState *env)
             /* just indicate that signals should be handled asap */
             break;
         case EXCP_PREFETCH_ABORT:
+            addr = env->cp15.c6_data;
+            goto do_segv;
         case EXCP_DATA_ABORT:
+            addr = env->cp15.c6_insn;
+            goto do_segv;
+        do_segv:
             {
                 info.si_signo = SIGSEGV;
                 info.si_errno = 0;
                 /* XXX: check env->error_code */
                 info.si_code = TARGET_SEGV_MAPERR;
-                info._sifields._sigfault._addr = env->cp15_6;
+                info._sifields._sigfault._addr = addr;
                 queue_signal(info.si_signo, &info);
             }
             break;
@@ -971,6 +977,405 @@ void cpu_loop(CPUPPCState *env)
 }
 #endif
 
+#ifdef TARGET_MIPS
+
+#define MIPS_SYS(name, args) args,
+
+static const uint8_t mips_syscall_args[] = {
+       MIPS_SYS(sys_syscall    , 0)    /* 4000 */
+       MIPS_SYS(sys_exit       , 1)
+       MIPS_SYS(sys_fork       , 0)
+       MIPS_SYS(sys_read       , 3)
+       MIPS_SYS(sys_write      , 3)
+       MIPS_SYS(sys_open       , 3)    /* 4005 */
+       MIPS_SYS(sys_close      , 1)
+       MIPS_SYS(sys_waitpid    , 3)
+       MIPS_SYS(sys_creat      , 2)
+       MIPS_SYS(sys_link       , 2)
+       MIPS_SYS(sys_unlink     , 1)    /* 4010 */
+       MIPS_SYS(sys_execve     , 0)
+       MIPS_SYS(sys_chdir      , 1)
+       MIPS_SYS(sys_time       , 1)
+       MIPS_SYS(sys_mknod      , 3)
+       MIPS_SYS(sys_chmod      , 2)    /* 4015 */
+       MIPS_SYS(sys_lchown     , 3)
+       MIPS_SYS(sys_ni_syscall , 0)
+       MIPS_SYS(sys_ni_syscall , 0)    /* was sys_stat */
+       MIPS_SYS(sys_lseek      , 3)
+       MIPS_SYS(sys_getpid     , 0)    /* 4020 */
+       MIPS_SYS(sys_mount      , 5)
+       MIPS_SYS(sys_oldumount  , 1)
+       MIPS_SYS(sys_setuid     , 1)
+       MIPS_SYS(sys_getuid     , 0)
+       MIPS_SYS(sys_stime      , 1)    /* 4025 */
+       MIPS_SYS(sys_ptrace     , 4)
+       MIPS_SYS(sys_alarm      , 1)
+       MIPS_SYS(sys_ni_syscall , 0)    /* was sys_fstat */
+       MIPS_SYS(sys_pause      , 0)
+       MIPS_SYS(sys_utime      , 2)    /* 4030 */
+       MIPS_SYS(sys_ni_syscall , 0)
+       MIPS_SYS(sys_ni_syscall , 0)
+       MIPS_SYS(sys_access     , 2)
+       MIPS_SYS(sys_nice       , 1)
+       MIPS_SYS(sys_ni_syscall , 0)    /* 4035 */
+       MIPS_SYS(sys_sync       , 0)
+       MIPS_SYS(sys_kill       , 2)
+       MIPS_SYS(sys_rename     , 2)
+       MIPS_SYS(sys_mkdir      , 2)
+       MIPS_SYS(sys_rmdir      , 1)    /* 4040 */
+       MIPS_SYS(sys_dup                , 1)
+       MIPS_SYS(sys_pipe       , 0)
+       MIPS_SYS(sys_times      , 1)
+       MIPS_SYS(sys_ni_syscall , 0)
+       MIPS_SYS(sys_brk                , 1)    /* 4045 */
+       MIPS_SYS(sys_setgid     , 1)
+       MIPS_SYS(sys_getgid     , 0)
+       MIPS_SYS(sys_ni_syscall , 0)    /* was signal(2) */
+       MIPS_SYS(sys_geteuid    , 0)
+       MIPS_SYS(sys_getegid    , 0)    /* 4050 */
+       MIPS_SYS(sys_acct       , 0)
+       MIPS_SYS(sys_umount     , 2)
+       MIPS_SYS(sys_ni_syscall , 0)
+       MIPS_SYS(sys_ioctl      , 3)
+       MIPS_SYS(sys_fcntl      , 3)    /* 4055 */
+       MIPS_SYS(sys_ni_syscall , 2)
+       MIPS_SYS(sys_setpgid    , 2)
+       MIPS_SYS(sys_ni_syscall , 0)
+       MIPS_SYS(sys_olduname   , 1)
+       MIPS_SYS(sys_umask      , 1)    /* 4060 */
+       MIPS_SYS(sys_chroot     , 1)
+       MIPS_SYS(sys_ustat      , 2)
+       MIPS_SYS(sys_dup2       , 2)
+       MIPS_SYS(sys_getppid    , 0)
+       MIPS_SYS(sys_getpgrp    , 0)    /* 4065 */
+       MIPS_SYS(sys_setsid     , 0)
+       MIPS_SYS(sys_sigaction  , 3)
+       MIPS_SYS(sys_sgetmask   , 0)
+       MIPS_SYS(sys_ssetmask   , 1)
+       MIPS_SYS(sys_setreuid   , 2)    /* 4070 */
+       MIPS_SYS(sys_setregid   , 2)
+       MIPS_SYS(sys_sigsuspend , 0)
+       MIPS_SYS(sys_sigpending , 1)
+       MIPS_SYS(sys_sethostname        , 2)
+       MIPS_SYS(sys_setrlimit  , 2)    /* 4075 */
+       MIPS_SYS(sys_getrlimit  , 2)
+       MIPS_SYS(sys_getrusage  , 2)
+       MIPS_SYS(sys_gettimeofday, 2)
+       MIPS_SYS(sys_settimeofday, 2)
+       MIPS_SYS(sys_getgroups  , 2)    /* 4080 */
+       MIPS_SYS(sys_setgroups  , 2)
+       MIPS_SYS(sys_ni_syscall , 0)    /* old_select */
+       MIPS_SYS(sys_symlink    , 2)
+       MIPS_SYS(sys_ni_syscall , 0)    /* was sys_lstat */
+       MIPS_SYS(sys_readlink   , 3)    /* 4085 */
+       MIPS_SYS(sys_uselib     , 1)
+       MIPS_SYS(sys_swapon     , 2)
+       MIPS_SYS(sys_reboot     , 3)
+       MIPS_SYS(old_readdir    , 3)
+       MIPS_SYS(old_mmap       , 6)    /* 4090 */
+       MIPS_SYS(sys_munmap     , 2)
+       MIPS_SYS(sys_truncate   , 2)
+       MIPS_SYS(sys_ftruncate  , 2)
+       MIPS_SYS(sys_fchmod     , 2)
+       MIPS_SYS(sys_fchown     , 3)    /* 4095 */
+       MIPS_SYS(sys_getpriority        , 2)
+       MIPS_SYS(sys_setpriority        , 3)
+       MIPS_SYS(sys_ni_syscall , 0)
+       MIPS_SYS(sys_statfs     , 2)
+       MIPS_SYS(sys_fstatfs    , 2)    /* 4100 */
+       MIPS_SYS(sys_ni_syscall , 0)    /* was ioperm(2) */
+       MIPS_SYS(sys_socketcall , 2)
+       MIPS_SYS(sys_syslog     , 3)
+       MIPS_SYS(sys_setitimer  , 3)
+       MIPS_SYS(sys_getitimer  , 2)    /* 4105 */
+       MIPS_SYS(sys_newstat    , 2)
+       MIPS_SYS(sys_newlstat   , 2)
+       MIPS_SYS(sys_newfstat   , 2)
+       MIPS_SYS(sys_uname      , 1)
+       MIPS_SYS(sys_ni_syscall , 0)    /* 4110 was iopl(2) */
+       MIPS_SYS(sys_vhangup    , 0)
+       MIPS_SYS(sys_ni_syscall , 0)    /* was sys_idle() */
+       MIPS_SYS(sys_ni_syscall , 0)    /* was sys_vm86 */
+       MIPS_SYS(sys_wait4      , 4)
+       MIPS_SYS(sys_swapoff    , 1)    /* 4115 */
+       MIPS_SYS(sys_sysinfo    , 1)
+       MIPS_SYS(sys_ipc                , 6)
+       MIPS_SYS(sys_fsync      , 1)
+       MIPS_SYS(sys_sigreturn  , 0)
+       MIPS_SYS(sys_clone      , 0)    /* 4120 */
+       MIPS_SYS(sys_setdomainname, 2)
+       MIPS_SYS(sys_newuname   , 1)
+       MIPS_SYS(sys_ni_syscall , 0)    /* sys_modify_ldt */
+       MIPS_SYS(sys_adjtimex   , 1)
+       MIPS_SYS(sys_mprotect   , 3)    /* 4125 */
+       MIPS_SYS(sys_sigprocmask        , 3)
+       MIPS_SYS(sys_ni_syscall , 0)    /* was create_module */
+       MIPS_SYS(sys_init_module        , 5)
+       MIPS_SYS(sys_delete_module, 1)
+       MIPS_SYS(sys_ni_syscall , 0)    /* 4130 was get_kernel_syms */
+       MIPS_SYS(sys_quotactl   , 0)
+       MIPS_SYS(sys_getpgid    , 1)
+       MIPS_SYS(sys_fchdir     , 1)
+       MIPS_SYS(sys_bdflush    , 2)
+       MIPS_SYS(sys_sysfs      , 3)    /* 4135 */
+       MIPS_SYS(sys_personality        , 1)
+       MIPS_SYS(sys_ni_syscall , 0)    /* for afs_syscall */
+       MIPS_SYS(sys_setfsuid   , 1)
+       MIPS_SYS(sys_setfsgid   , 1)
+       MIPS_SYS(sys_llseek     , 5)    /* 4140 */
+       MIPS_SYS(sys_getdents   , 3)
+       MIPS_SYS(sys_select     , 5)
+       MIPS_SYS(sys_flock      , 2)
+       MIPS_SYS(sys_msync      , 3)
+       MIPS_SYS(sys_readv      , 3)    /* 4145 */
+       MIPS_SYS(sys_writev     , 3)
+       MIPS_SYS(sys_cacheflush , 3)
+       MIPS_SYS(sys_cachectl   , 3)
+       MIPS_SYS(sys_sysmips    , 4)
+       MIPS_SYS(sys_ni_syscall , 0)    /* 4150 */
+       MIPS_SYS(sys_getsid     , 1)
+       MIPS_SYS(sys_fdatasync  , 0)
+       MIPS_SYS(sys_sysctl     , 1)
+       MIPS_SYS(sys_mlock      , 2)
+       MIPS_SYS(sys_munlock    , 2)    /* 4155 */
+       MIPS_SYS(sys_mlockall   , 1)
+       MIPS_SYS(sys_munlockall , 0)
+       MIPS_SYS(sys_sched_setparam, 2)
+       MIPS_SYS(sys_sched_getparam, 2)
+       MIPS_SYS(sys_sched_setscheduler, 3)     /* 4160 */
+       MIPS_SYS(sys_sched_getscheduler, 1)
+       MIPS_SYS(sys_sched_yield        , 0)
+       MIPS_SYS(sys_sched_get_priority_max, 1)
+       MIPS_SYS(sys_sched_get_priority_min, 1)
+       MIPS_SYS(sys_sched_rr_get_interval, 2)  /* 4165 */
+       MIPS_SYS(sys_nanosleep, 2)
+       MIPS_SYS(sys_mremap     , 4)
+       MIPS_SYS(sys_accept     , 3)
+       MIPS_SYS(sys_bind       , 3)
+       MIPS_SYS(sys_connect    , 3)    /* 4170 */
+       MIPS_SYS(sys_getpeername        , 3)
+       MIPS_SYS(sys_getsockname        , 3)
+       MIPS_SYS(sys_getsockopt , 5)
+       MIPS_SYS(sys_listen     , 2)
+       MIPS_SYS(sys_recv       , 4)    /* 4175 */
+       MIPS_SYS(sys_recvfrom   , 6)
+       MIPS_SYS(sys_recvmsg    , 3)
+       MIPS_SYS(sys_send       , 4)
+       MIPS_SYS(sys_sendmsg    , 3)
+       MIPS_SYS(sys_sendto     , 6)    /* 4180 */
+       MIPS_SYS(sys_setsockopt , 5)
+       MIPS_SYS(sys_shutdown   , 2)
+       MIPS_SYS(sys_socket     , 3)
+       MIPS_SYS(sys_socketpair , 4)
+       MIPS_SYS(sys_setresuid  , 3)    /* 4185 */
+       MIPS_SYS(sys_getresuid  , 3)
+       MIPS_SYS(sys_ni_syscall , 0)    /* was sys_query_module */
+       MIPS_SYS(sys_poll       , 3)
+       MIPS_SYS(sys_nfsservctl , 3)
+       MIPS_SYS(sys_setresgid  , 3)    /* 4190 */
+       MIPS_SYS(sys_getresgid  , 3)
+       MIPS_SYS(sys_prctl      , 5)
+       MIPS_SYS(sys_rt_sigreturn, 0)
+       MIPS_SYS(sys_rt_sigaction, 4)
+       MIPS_SYS(sys_rt_sigprocmask, 4) /* 4195 */
+       MIPS_SYS(sys_rt_sigpending, 2)
+       MIPS_SYS(sys_rt_sigtimedwait, 4)
+       MIPS_SYS(sys_rt_sigqueueinfo, 3)
+       MIPS_SYS(sys_rt_sigsuspend, 0)
+       MIPS_SYS(sys_pread64    , 6)    /* 4200 */
+       MIPS_SYS(sys_pwrite64   , 6)
+       MIPS_SYS(sys_chown      , 3)
+       MIPS_SYS(sys_getcwd     , 2)
+       MIPS_SYS(sys_capget     , 2)
+       MIPS_SYS(sys_capset     , 2)    /* 4205 */
+       MIPS_SYS(sys_sigaltstack        , 0)
+       MIPS_SYS(sys_sendfile   , 4)
+       MIPS_SYS(sys_ni_syscall , 0)
+       MIPS_SYS(sys_ni_syscall , 0)
+       MIPS_SYS(sys_mmap2      , 6)    /* 4210 */
+       MIPS_SYS(sys_truncate64 , 4)
+       MIPS_SYS(sys_ftruncate64        , 4)
+       MIPS_SYS(sys_stat64     , 2)
+       MIPS_SYS(sys_lstat64    , 2)
+       MIPS_SYS(sys_fstat64    , 2)    /* 4215 */
+       MIPS_SYS(sys_pivot_root , 2)
+       MIPS_SYS(sys_mincore    , 3)
+       MIPS_SYS(sys_madvise    , 3)
+       MIPS_SYS(sys_getdents64 , 3)
+       MIPS_SYS(sys_fcntl64    , 3)    /* 4220 */
+       MIPS_SYS(sys_ni_syscall , 0)
+       MIPS_SYS(sys_gettid     , 0)
+       MIPS_SYS(sys_readahead  , 5)
+       MIPS_SYS(sys_setxattr   , 5)
+       MIPS_SYS(sys_lsetxattr  , 5)    /* 4225 */
+       MIPS_SYS(sys_fsetxattr  , 5)
+       MIPS_SYS(sys_getxattr   , 4)
+       MIPS_SYS(sys_lgetxattr  , 4)
+       MIPS_SYS(sys_fgetxattr  , 4)
+       MIPS_SYS(sys_listxattr  , 3)    /* 4230 */
+       MIPS_SYS(sys_llistxattr , 3)
+       MIPS_SYS(sys_flistxattr , 3)
+       MIPS_SYS(sys_removexattr        , 2)
+       MIPS_SYS(sys_lremovexattr, 2)
+       MIPS_SYS(sys_fremovexattr, 2)   /* 4235 */
+       MIPS_SYS(sys_tkill      , 2)
+       MIPS_SYS(sys_sendfile64 , 5)
+       MIPS_SYS(sys_futex      , 2)
+       MIPS_SYS(sys_sched_setaffinity, 3)
+       MIPS_SYS(sys_sched_getaffinity, 3)      /* 4240 */
+       MIPS_SYS(sys_io_setup   , 2)
+       MIPS_SYS(sys_io_destroy , 1)
+       MIPS_SYS(sys_io_getevents, 5)
+       MIPS_SYS(sys_io_submit  , 3)
+       MIPS_SYS(sys_io_cancel  , 3)    /* 4245 */
+       MIPS_SYS(sys_exit_group , 1)
+       MIPS_SYS(sys_lookup_dcookie, 3)
+       MIPS_SYS(sys_epoll_create, 1)
+       MIPS_SYS(sys_epoll_ctl  , 4)
+       MIPS_SYS(sys_epoll_wait , 3)    /* 4250 */
+       MIPS_SYS(sys_remap_file_pages, 5)
+       MIPS_SYS(sys_set_tid_address, 1)
+       MIPS_SYS(sys_restart_syscall, 0)
+       MIPS_SYS(sys_fadvise64_64, 7)
+       MIPS_SYS(sys_statfs64   , 3)    /* 4255 */
+       MIPS_SYS(sys_fstatfs64  , 2)
+       MIPS_SYS(sys_timer_create, 3)
+       MIPS_SYS(sys_timer_settime, 4)
+       MIPS_SYS(sys_timer_gettime, 2)
+       MIPS_SYS(sys_timer_getoverrun, 1)       /* 4260 */
+       MIPS_SYS(sys_timer_delete, 1)
+       MIPS_SYS(sys_clock_settime, 2)
+       MIPS_SYS(sys_clock_gettime, 2)
+       MIPS_SYS(sys_clock_getres, 2)
+       MIPS_SYS(sys_clock_nanosleep, 4)        /* 4265 */
+       MIPS_SYS(sys_tgkill     , 3)
+       MIPS_SYS(sys_utimes     , 2)
+       MIPS_SYS(sys_mbind      , 4)
+       MIPS_SYS(sys_ni_syscall , 0)    /* sys_get_mempolicy */
+       MIPS_SYS(sys_ni_syscall , 0)    /* 4270 sys_set_mempolicy */
+       MIPS_SYS(sys_mq_open    , 4)
+       MIPS_SYS(sys_mq_unlink  , 1)
+       MIPS_SYS(sys_mq_timedsend, 5)
+       MIPS_SYS(sys_mq_timedreceive, 5)
+       MIPS_SYS(sys_mq_notify  , 2)    /* 4275 */
+       MIPS_SYS(sys_mq_getsetattr, 3)
+       MIPS_SYS(sys_ni_syscall , 0)    /* sys_vserver */
+       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_keyctl     , 5)
+};
+
+#undef MIPS_SYS
+
+void cpu_loop(CPUMIPSState *env)
+{
+    target_siginfo_t info;
+    int trapnr, ret, nb_args;
+    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;
+                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 */
+                        if (get_user(arg5, (target_ulong *)(sp_reg + 16))) {
+                            ret = -EFAULT;
+                            goto fail;
+                        }
+                        if (nb_args >= 6) {
+                            if (get_user(arg6, (target_ulong *)(sp_reg + 20))) {
+                                ret = -EFAULT;
+                                goto fail;
+                            }
+                        } 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);
+                }
+                fail:
+                env->PC += 4;
+                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;
+                }
+            }
+            break;
+        case EXCP_CpU:
+        case EXCP_RI:
+            {
+                uint32_t insn, op;
+
+                if (get_user(insn, (uint32_t *)env->PC) < 0)
+                    goto sigill;
+                op = insn >> 26;
+                //                printf("insn=%08x op=%02x\n", insn, op);
+                /* XXX: totally dummy FP ops just to be able to launch
+                   a few executables */
+                switch(op) {
+                case 0x31: /* LWC1 */
+                    env->PC += 4;
+                    break;
+                case 0x39: /* SWC1 */
+                    env->PC += 4;
+                    break;
+                case 0x11:
+                    switch((insn >> 21) & 0x1f) {
+                    case 0x02: /* CFC1 */
+                        env->PC += 4;
+                        break;
+                    default:
+                        goto sigill;
+                    }
+                    break;
+                default:
+                sigill:
+                    info.si_signo = TARGET_SIGILL;
+                    info.si_errno = 0;
+                    info.si_code = 0;
+                    queue_signal(info.si_signo, &info);
+                    break;
+                }
+            }
+            break;
+        default:
+            //        error:
+            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 
+                    trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            abort();
+        }
+        process_pending_signals(env);
+    }
+}
+#endif
+
 void usage(void)
 {
     printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2005 Fabrice Bellard\n"
@@ -978,7 +1383,7 @@ void usage(void)
            "Linux CPU emulator (compiled for %s emulation)\n"
            "\n"
            "-h           print this help\n"
-           "-g           wait gdb connection to port %d\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"
            "\n"
@@ -989,7 +1394,6 @@ void usage(void)
            "-d options   activate log (logfile=%s)\n"
            "-p pagesize  set the host page size to 'pagesize'\n",
            TARGET_ARCH,
-           DEFAULT_GDBSTUB_PORT,
            interp_prefix, 
            x86_stack_size,
            DEBUG_LOGFILE);
@@ -998,8 +1402,6 @@ void usage(void)
 
 /* XXX: currently only used for async signals (see signal.c) */
 CPUState *global_env;
-/* used only if single thread */
-CPUState *cpu_single_env = NULL;
 
 /* used to free thread contexts */
 TaskState *first_task_state;
@@ -1013,7 +1415,7 @@ int main(int argc, char **argv)
     CPUState *env;
     int optind;
     const char *r;
-    int use_gdbstub = 0;
+    int gdbstub_port = 0;
     
     if (argc <= 1)
         usage();
@@ -1068,7 +1470,7 @@ int main(int argc, char **argv)
                 exit(1);
             }
         } else if (!strcmp(r, "g")) {
-            use_gdbstub = 1;
+            gdbstub_port = atoi(argv[optind++]);
         } else 
 #ifdef USE_CODE_COPY
         if (!strcmp(r, "no-code-copy")) {
@@ -1095,6 +1497,7 @@ int main(int argc, char **argv)
     /* NOTE: we need to init the CPU at this stage to get
        qemu_host_page_size */
     env = cpu_init();
+    global_env = env;
     
     if (elf_exec(filename, argv+optind, environ, regs, info) != 0) {
        printf("Error loading %s\n", filename);
@@ -1117,8 +1520,6 @@ int main(int argc, char **argv)
     syscall_init();
     signal_init();
 
-    global_env = env;
-
     /* build Task State */
     memset(ts, 0, sizeof(TaskState));
     env->opaque = ts;
@@ -1193,10 +1594,10 @@ int main(int argc, char **argv)
 #elif defined(TARGET_ARM)
     {
         int i;
+        cpsr_write(env, regs->uregs[16], 0xffffffff);
         for(i = 0; i < 16; i++) {
             env->regs[i] = regs->uregs[i];
         }
-        env->cpsr = regs->uregs[16];
         ts->stack_base = info->start_stack;
         ts->heap_base = info->brk;
         /* This will be filled in on the first SYS_HEAPINFO call.  */
@@ -1229,10 +1630,10 @@ int main(int argc, char **argv)
         //        ppc_find_by_name("604e", &def);
         //        ppc_find_by_name("604", &def);
         if (def == NULL) {
-            cpu_abort(cpu_single_env,
+            cpu_abort(env,
                       "Unable to find PowerPC CPU definition\n");
         }
-        cpu_ppc_register(cpu_single_env, def);
+        cpu_ppc_register(env, def);
 
         for (i = 0; i < 32; i++) {
             if (i != 12 && i != 6 && i != 13)
@@ -1243,12 +1644,21 @@ int main(int argc, char **argv)
             env->gpr[i] = regs->gpr[i];
         }
     }
+#elif defined(TARGET_MIPS)
+    {
+        int i;
+
+        for(i = 0; i < 32; i++) {
+            env->gpr[i] = regs->regs[i];
+        }
+        env->PC = regs->cp0_epc;
+    }
 #else
 #error unsupported target CPU
 #endif
 
-    if (use_gdbstub) {
-        gdbserver_start (DEFAULT_GDBSTUB_PORT);
+    if (gdbstub_port) {
+        gdbserver_start (gdbstub_port);
         gdb_handlesig(env, 0);
     }
     cpu_loop(env);
diff --git a/qemu/linux-user/mips/syscall.h b/qemu/linux-user/mips/syscall.h
new file mode 100644 (file)
index 0000000..4b3c7d6
--- /dev/null
@@ -0,0 +1,23 @@
+
+/* this struct defines the way the registers are stored on the
+   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];
+
+       /* 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;
+};
+
+#define UNAME_MACHINE "mips"
diff --git a/qemu/linux-user/mips/syscall_nr.h b/qemu/linux-user/mips/syscall_nr.h
new file mode 100644 (file)
index 0000000..3593e65
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * 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_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_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_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_break                        (TARGET_NR_Linux +  17)
+#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_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_stime                        (TARGET_NR_Linux +  25)
+#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_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_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_mkdir                        (TARGET_NR_Linux +  39)
+#define TARGET_NR_rmdir                        (TARGET_NR_Linux +  40)
+#define TARGET_NR_dup                  (TARGET_NR_Linux +  41)
+#define TARGET_NR_pipe                 (TARGET_NR_Linux +  42)
+#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_acct                 (TARGET_NR_Linux +  51)
+#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_umask                        (TARGET_NR_Linux +  60)
+#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_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_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_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_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_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_iopl                 (TARGET_NR_Linux + 110)
+#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_ipc                  (TARGET_NR_Linux + 117)
+#define TARGET_NR_fsync                        (TARGET_NR_Linux + 118)
+#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_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_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_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_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_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_bind                 (TARGET_NR_Linux + 169)
+#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_recv                 (TARGET_NR_Linux + 175)
+#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_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_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_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_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_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_mmap2                        (TARGET_NR_Linux + 210)
+#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_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_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_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_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_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_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_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_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_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_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_request_key          (TARGET_NR_Linux + 281)
+#define TARGET_NR_keyctl                       (TARGET_NR_Linux + 282)
+
diff --git a/qemu/linux-user/mips/termbits.h b/qemu/linux-user/mips/termbits.h
new file mode 100644 (file)
index 0000000..fea7940
--- /dev/null
@@ -0,0 +1,229 @@
+/* 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
+
+/* 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_B57600  0010001
+#define  TARGET_B115200 0010002
+#define  TARGET_B230400 0010003
+#define  TARGET_B460800 0010004
+#define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
+#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_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
+
+/* 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_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
+
+/* 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 */
index a7c06c9..29933bd 100644 (file)
@@ -1003,7 +1003,7 @@ setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
        __put_user_error(env->regs[14], &sc->arm_lr, err);
        __put_user_error(env->regs[15], &sc->arm_pc, err);
 #ifdef TARGET_CONFIG_CPU_32
-       __put_user_error(env->cpsr, &sc->arm_cpsr, err);
+       __put_user_error(cpsr_read(env), &sc->arm_cpsr, err);
 #endif
 
        __put_user_error(/* current->thread.trap_no */ 0, &sc->trap_no, err);
@@ -1040,9 +1040,9 @@ setup_return(CPUState *env, struct emulated_sigaction *ka,
        target_ulong retcode;
        int thumb = 0;
 #if defined(TARGET_CONFIG_CPU_32)
+#if 0
        target_ulong cpsr = env->cpsr;
 
-#if 0
        /*
         * Maybe we need to deliver a 32-bit signal to a 26-bit task.
         */
@@ -1088,9 +1088,11 @@ setup_return(CPUState *env, struct emulated_sigaction *ka,
        env->regs[14] = retcode;
        env->regs[15] = handler & (thumb ? ~1 : ~3);
 
+#if 0
 #ifdef TARGET_CONFIG_CPU_32
        env->cpsr = cpsr;
 #endif
+#endif
 
        return 0;
 }
@@ -1157,6 +1159,7 @@ static int
 restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
 {
        int err = 0;
+        uint32_t cpsr;
 
        __get_user_error(env->regs[0], &sc->arm_r0, err);
        __get_user_error(env->regs[1], &sc->arm_r1, err);
@@ -1175,7 +1178,8 @@ restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
        __get_user_error(env->regs[14], &sc->arm_lr, err);
        __get_user_error(env->regs[15], &sc->arm_pc, err);
 #ifdef TARGET_CONFIG_CPU_32
-       __get_user_error(env->cpsr, &sc->arm_cpsr, err);
+       __get_user_error(cpsr, &sc->arm_cpsr, err);
+        cpsr_write(env, cpsr, 0xffffffff);
 #endif
 
        err |= !valid_user_regs(env);
index e51f513..164eb39 100644 (file)
@@ -42,6 +42,7 @@
 #include <sys/poll.h>
 #include <sys/times.h>
 #include <sys/shm.h>
+#include <sys/statfs.h>
 #include <utime.h>
 #include <sys/sysinfo.h>
 //#include <sys/user.h>
@@ -202,8 +203,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5)       \
 
 #define __NR_sys_uname __NR_uname
 #define __NR_sys_getcwd1 __NR_getcwd
-#define __NR_sys_statfs __NR_statfs
-#define __NR_sys_fstatfs __NR_fstatfs
 #define __NR_sys_getdents __NR_getdents
 #define __NR_sys_getdents64 __NR_getdents64
 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
@@ -225,8 +224,6 @@ _syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count);
 _syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count);
 _syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
           loff_t *, res, uint, wh);
-_syscall2(int,sys_statfs,const char *,path,struct kernel_statfs *,buf)
-_syscall2(int,sys_fstatfs,int,fd,struct kernel_statfs *,buf)
 _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
 #ifdef __NR_exit_group
 _syscall1(int,exit_group,int,error_code)
@@ -460,7 +457,7 @@ static inline void target_to_host_cmsg(struct msghdr *msgh,
         space += CMSG_SPACE(len);
         if (space > msgh->msg_controllen) {
             space -= CMSG_SPACE(len);
-            gemu_log("Host cmsg overflow");
+            gemu_log("Host cmsg overflow\n");
             break;
         }
 
@@ -503,7 +500,7 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh,
         space += TARGET_CMSG_SPACE(len);
         if (space > tswapl(target_msgh->msg_controllen)) {
             space -= TARGET_CMSG_SPACE(len);
-            gemu_log("Target cmsg overflow");
+            gemu_log("Target cmsg overflow\n");
             break;
         }
 
@@ -1497,6 +1494,8 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
         new_env->regs[0] = 0;
 #elif defined(TARGET_SPARC)
         printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
+#elif defined(TARGET_MIPS)
+        printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
 #elif defined(TARGET_PPC)
         if (!newsp)
             newsp = env->gpr[1];
@@ -1657,7 +1656,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
 {
     long ret;
     struct stat st;
-    struct kernel_statfs *stfs;
+    struct statfs stfs;
     
 #ifdef DEBUG
     gemu_log("syscall %d", num);
@@ -2184,6 +2183,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
             ret = get_errno(settimeofday(&tv, NULL));
         }
         break;
+#ifdef TARGET_NR_select
     case TARGET_NR_select:
         {
             struct target_sel_arg_struct *sel = (void *)arg1;
@@ -2196,6 +2196,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
                             (void *)sel->exp, (void *)sel->tvp);
         }
         break;
+#endif
     case TARGET_NR_symlink:
         ret = get_errno(symlink((const char *)arg1, (const char *)arg2));
         break;
@@ -2294,26 +2295,47 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
         goto unimplemented;
 #endif
     case TARGET_NR_statfs:
-        stfs = (void *)arg2;
-        ret = get_errno(sys_statfs(path((const char *)arg1), stfs));
+        ret = get_errno(statfs(path((const char *)arg1), &stfs));
     convert_statfs:
         if (!is_error(ret)) {
-            tswap32s(&stfs->f_type);
-            tswap32s(&stfs->f_bsize);
-            tswap32s(&stfs->f_blocks);
-            tswap32s(&stfs->f_bfree);
-            tswap32s(&stfs->f_bavail);
-            tswap32s(&stfs->f_files);
-            tswap32s(&stfs->f_ffree);
-            tswap32s(&stfs->f_fsid.val[0]);
-            tswap32s(&stfs->f_fsid.val[1]);
-            tswap32s(&stfs->f_namelen);
+            struct target_statfs *target_stfs = (void *)arg2;
+            
+            put_user(stfs.f_type, &target_stfs->f_type);
+            put_user(stfs.f_bsize, &target_stfs->f_bsize);
+            put_user(stfs.f_blocks, &target_stfs->f_blocks);
+            put_user(stfs.f_bfree, &target_stfs->f_bfree);
+            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_namelen, &target_stfs->f_namelen);
         }
         break;
     case TARGET_NR_fstatfs:
-        stfs = (void *)arg2;
-        ret = get_errno(sys_fstatfs(arg1, stfs));
+        ret = get_errno(fstatfs(arg1, &stfs));
         goto convert_statfs;
+#ifdef TARGET_NR_statfs64
+    case TARGET_NR_statfs64:
+        ret = get_errno(statfs(path((const char *)arg1), &stfs));
+    convert_statfs64:
+        if (!is_error(ret)) {
+            struct target_statfs64 *target_stfs = (void *)arg3;
+
+            put_user(stfs.f_type, &target_stfs->f_type);
+            put_user(stfs.f_bsize, &target_stfs->f_bsize);
+            put_user(stfs.f_blocks, &target_stfs->f_blocks);
+            put_user(stfs.f_bfree, &target_stfs->f_bfree);
+            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_namelen, &target_stfs->f_namelen);
+        }
+        break;
+    case TARGET_NR_fstatfs64:
+        ret = get_errno(fstatfs(arg1, &stfs));
+        goto convert_statfs64;
+#endif
 #ifdef TARGET_NR_ioperm
     case TARGET_NR_ioperm:
         goto unimplemented;
@@ -2802,9 +2824,11 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
     case TARGET_NR_putpmsg:
         goto unimplemented;
 #endif
+#ifdef TARGET_NR_vfork
     case TARGET_NR_vfork:
         ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
         break;
+#endif
 #ifdef TARGET_NR_ugetrlimit
     case TARGET_NR_ugetrlimit:
     {
index ae212ec..68f7e7f 100644 (file)
@@ -57,7 +57,8 @@
 #define TARGET_IOC_WRITE  1U
 #define TARGET_IOC_READ          2U
 
-#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_SPARC)
+#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
+      defined(TARGET_SPARC) || defined(TARGET_MIPS)
 
 #define TARGET_IOC_SIZEBITS    13
 #define TARGET_IOC_DIRBITS     3
@@ -292,9 +293,26 @@ 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)
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS)
 
-#if !defined(TARGET_SPARC)
+#if defined(TARGET_SPARC)
+#define TARGET_SA_NOCLDSTOP    8u
+#define TARGET_SA_NOCLDWAIT    0x100u
+#define TARGET_SA_SIGINFO      0x200u
+#define TARGET_SA_ONSTACK      1u
+#define TARGET_SA_RESTART      2u
+#define TARGET_SA_NODEFER      0x20u
+#define TARGET_SA_RESETHAND    4u
+#elif defined(TARGET_MIPS)
+#define TARGET_SA_NOCLDSTOP    0x00000001
+#define TARGET_SA_NOCLDWAIT    0x00010000
+#define TARGET_SA_SIGINFO      0x00000008
+#define TARGET_SA_ONSTACK      0x08000000
+#define TARGET_SA_NODEFER      0x40000000
+#define TARGET_SA_RESTART      0x10000000
+#define TARGET_SA_RESETHAND    0x80000000
+#define TARGET_SA_RESTORER     0x04000000      /* Only for o32 */
+#else
 #define TARGET_SA_NOCLDSTOP    0x00000001
 #define TARGET_SA_NOCLDWAIT    0x00000002 /* not supported yet */
 #define TARGET_SA_SIGINFO      0x00000004
@@ -303,14 +321,6 @@ int do_sigaction(int sig, const struct target_sigaction *act,
 #define TARGET_SA_NODEFER      0x40000000
 #define TARGET_SA_RESETHAND    0x80000000
 #define TARGET_SA_RESTORER     0x04000000
-#else /* TARGET_SPARC */
-#define TARGET_SA_NOCLDSTOP    8u
-#define TARGET_SA_NOCLDWAIT    0x100u
-#define TARGET_SA_SIGINFO      0x200u
-#define TARGET_SA_ONSTACK      1u
-#define TARGET_SA_RESTART      2u
-#define TARGET_SA_NODEFER      0x20u
-#define TARGET_SA_RESETHAND    4u
 #endif
 
 #if defined(TARGET_SPARC)
@@ -353,6 +363,49 @@ int do_sigaction(int sig, const struct target_sigaction *act,
 #define TARGET_SIG_UNBLOCK        0x02 /* for unblocking signals */
 #define TARGET_SIG_SETMASK        0x04 /* for setting the signal mask */
 
+#elif defined(TARGET_MIPS)
+
+#define TARGET_SIGHUP           1      /* Hangup (POSIX).  */
+#define TARGET_SIGINT           2      /* Interrupt (ANSI).  */
+#define TARGET_SIGQUIT          3      /* Quit (POSIX).  */
+#define TARGET_SIGILL           4      /* Illegal instruction (ANSI).  */
+#define TARGET_SIGTRAP          5      /* Trace trap (POSIX).  */
+#define TARGET_SIGIOT           6      /* IOT trap (4.2 BSD).  */
+#define TARGET_SIGABRT          TARGET_SIGIOT  /* Abort (ANSI).  */
+#define TARGET_SIGEMT           7
+#define TARGET_SIGSTKFLT        7 /* XXX: incorrect */
+#define TARGET_SIGFPE           8      /* Floating-point exception (ANSI).  */
+#define TARGET_SIGKILL          9      /* Kill, unblockable (POSIX).  */
+#define TARGET_SIGBUS          10      /* BUS error (4.2 BSD).  */
+#define TARGET_SIGSEGV         11      /* Segmentation violation (ANSI).  */
+#define TARGET_SIGSYS          12
+#define TARGET_SIGPIPE         13      /* Broken pipe (POSIX).  */
+#define TARGET_SIGALRM         14      /* Alarm clock (POSIX).  */
+#define TARGET_SIGTERM         15      /* Termination (ANSI).  */
+#define TARGET_SIGUSR1         16      /* User-defined signal 1 (POSIX).  */
+#define TARGET_SIGUSR2         17      /* User-defined signal 2 (POSIX).  */
+#define TARGET_SIGCHLD         18      /* Child status has changed (POSIX).  */
+#define TARGET_SIGCLD          TARGET_SIGCHLD  /* Same as TARGET_SIGCHLD (System V).  */
+#define TARGET_SIGPWR          19      /* Power failure restart (System V).  */
+#define TARGET_SIGWINCH        20      /* Window size change (4.3 BSD, Sun).  */
+#define TARGET_SIGURG          21      /* Urgent condition on socket (4.2 BSD).  */
+#define TARGET_SIGIO           22      /* I/O now possible (4.2 BSD).  */
+#define TARGET_SIGPOLL         TARGET_SIGIO    /* Pollable event occurred (System V).  */
+#define TARGET_SIGSTOP         23      /* Stop, unblockable (POSIX).  */
+#define TARGET_SIGTSTP         24      /* Keyboard stop (POSIX).  */
+#define TARGET_SIGCONT         25      /* Continue (POSIX).  */
+#define TARGET_SIGTTIN         26      /* Background read from tty (POSIX).  */
+#define TARGET_SIGTTOU         27      /* Background write to tty (POSIX).  */
+#define TARGET_SIGVTALRM       28      /* Virtual alarm clock (4.2 BSD).  */
+#define TARGET_SIGPROF         29      /* Profiling alarm clock (4.2 BSD).  */
+#define TARGET_SIGXCPU         30      /* CPU limit exceeded (4.2 BSD).  */
+#define TARGET_SIGXFSZ         31      /* File size limit exceeded (4.2 BSD).  */
+#define TARGET_SIGRTMIN         32
+
+#define TARGET_SIG_BLOCK       1       /* for blocking signals */
+#define TARGET_SIG_UNBLOCK     2       /* for unblocking signals */
+#define TARGET_SIG_SETMASK     3       /* for setting the signal mask */
+
 #else
 
 #define TARGET_SIGHUP           1
@@ -794,13 +847,21 @@ struct target_winsize {
 #define TARGET_MAP_PRIVATE     0x02            /* Changes are private */
 #define TARGET_MAP_TYPE        0x0f            /* Mask for type of mapping */
 #define TARGET_MAP_FIXED       0x10            /* Interpret addr exactly */
+#if defined(TARGET_MIPS)
+#define TARGET_MAP_ANONYMOUS   0x0800          /* don't use a file */
+#define TARGET_MAP_GROWSDOWN   0x1000          /* stack-like segment */
+#define TARGET_MAP_DENYWRITE   0x2000          /* ETXTBSY */
+#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 */
+#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 */
 #define TARGET_MAP_LOCKED      0x2000          /* pages are locked */
 #define TARGET_MAP_NORESERVE   0x4000          /* don't check for reservations */
+#endif
 
 #if defined(TARGET_I386) || defined(TARGET_ARM)
 struct target_stat {
@@ -967,7 +1028,141 @@ struct target_stat64 {
         target_ulong    __unused5;
 };
 
-#endif /* defined(TARGET_PPC) */
+#elif defined(TARGET_MIPS)
+
+struct target_stat {
+       unsigned        st_dev;
+       target_long     st_pad1[3];             /* Reserved for network id */
+       target_ulong    st_ino;
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+       int             st_uid;
+       int             st_gid;
+       unsigned        st_rdev;
+       target_long     st_pad2[2];
+       target_long     st_size;
+       target_long     st_pad3;
+       /*
+        * Actually this should be timestruc_t st_atime, st_mtime and st_ctime
+        * but we don't have it under Linux.
+        */
+       target_long             target_st_atime;
+       target_long             target_st_atime_nsec;
+       target_long             target_st_mtime;
+       target_long             target_st_mtime_nsec;
+       target_long             target_st_ctime;
+       target_long             target_st_ctime_nsec;
+       target_long             st_blksize;
+       target_long             st_blocks;
+       target_long             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 {
+       target_ulong    st_dev;
+       target_ulong    st_pad0[3];     /* Reserved for st_dev expansion  */
+
+       uint64_t        st_ino;
+
+        unsigned int   st_mode;
+        unsigned int   st_nlink;
+
+       int             st_uid;
+       int             st_gid;
+
+       target_ulong    st_rdev;
+       target_ulong    st_pad1[3];     /* Reserved for st_rdev expansion  */
+
+       int64_t         st_size;
+
+       /*
+        * Actually this should be timestruc_t st_atime, st_mtime and st_ctime
+        * but we don't have it under Linux.
+        */
+       target_long     target_st_atime;
+       target_ulong    target_st_atime_nsec;   /* Reserved for st_atime expansion  */
+
+       target_long     target_st_mtime;
+       target_ulong    target_st_mtime_nsec;   /* Reserved for st_mtime expansion  */
+
+       target_long     target_st_ctime;
+       target_ulong    target_st_ctime_nsec;   /* Reserved for st_ctime expansion  */
+
+       target_ulong    st_blksize;
+       target_ulong    st_pad2;
+
+       int64_t         st_blocks;
+};
+#else
+#error unsupported CPU
+#endif
+
+#ifdef TARGET_MIPS
+struct target_statfs {
+       target_long             f_type;
+       target_long             f_bsize;
+       target_long             f_frsize;       /* Fragment size - unsupported */
+       target_long             f_blocks;
+       target_long             f_bfree;
+       target_long             f_files;
+       target_long             f_ffree;
+       target_long             f_bavail;
+
+       /* Linux specials */
+       int     f_fsid;
+       target_long             f_namelen;
+       target_long             f_spare[6];
+};
+
+struct target_statfs64 {
+       uint32_t        f_type;
+       uint32_t        f_bsize;
+       uint32_t        f_frsize;       /* Fragment size - unsupported */
+       uint32_t        __pad;
+       uint64_t        f_blocks;
+       uint64_t        f_bfree;
+       uint64_t        f_files;
+       uint64_t        f_ffree;
+       uint64_t        f_bavail;
+       int f_fsid;
+       uint32_t        f_namelen;
+       uint32_t        f_spare[6];
+};
+#else
+struct target_statfs {
+       uint32_t f_type;
+       uint32_t f_bsize;
+       uint32_t f_blocks;
+       uint32_t f_bfree;
+       uint32_t f_bavail;
+       uint32_t f_files;
+       uint32_t f_ffree;
+       int f_fsid;
+       uint32_t f_namelen;
+       uint32_t f_frsize;
+       uint32_t f_spare[5];
+};
+
+struct target_statfs64 {
+       uint32_t f_type;
+       uint32_t f_bsize;
+       uint64_t f_blocks;
+       uint64_t f_bfree;
+       uint64_t f_bavail;
+       uint64_t f_files;
+       uint64_t f_ffree;
+       int f_fsid;
+        uint32_t f_namelen;
+       uint32_t f_frsize;
+       uint32_t f_spare[5];
+};
+#endif
+
 
 #define TARGET_F_DUPFD         0       /* dup */
 #define TARGET_F_GETFD         1       /* get close_on_exec */
@@ -1007,7 +1202,7 @@ struct target_stat64 {
 #define TARGET_O_TRUNC           01000 /* not fcntl */
 #define TARGET_O_APPEND          02000
 #define TARGET_O_NONBLOCK        04000
-#define TARGET_O_NDELAY        O_NONBLOCK
+#define TARGET_O_NDELAY        TARGET_O_NONBLOCK
 #define TARGET_O_SYNC           010000
 #define TARGET_FASYNC           020000 /* fcntl, for BSD compatibility */
 #define TARGET_O_DIRECTORY      040000 /* must be a directory */
@@ -1025,7 +1220,7 @@ struct target_stat64 {
 #define TARGET_O_TRUNC           01000 /* not fcntl */
 #define TARGET_O_APPEND          02000
 #define TARGET_O_NONBLOCK        04000
-#define TARGET_O_NDELAY        O_NONBLOCK
+#define TARGET_O_NDELAY        TARGET_O_NONBLOCK
 #define TARGET_O_SYNC           010000
 #define TARGET_FASYNC           020000 /* fcntl, for BSD compatibility */
 #define TARGET_O_DIRECTORY      040000 /* must be a directory */
@@ -1044,12 +1239,31 @@ struct target_stat64 {
 #define TARGET_O_EXCL          0x0800  /* not fcntl */
 #define TARGET_O_SYNC          0x2000
 #define TARGET_O_NONBLOCK      0x4000
-#define TARGET_O_NDELAY        (0x0004 | O_NONBLOCK)
+#define TARGET_O_NDELAY        (0x0004 | TARGET_O_NONBLOCK)
 #define TARGET_O_NOCTTY        0x8000  /* not fcntl */
 #define TARGET_O_DIRECTORY     0x10000 /* must be a directory */
 #define TARGET_O_NOFOLLOW      0x20000 /* don't follow links */
 #define TARGET_O_LARGEFILE     0x40000
 #define TARGET_O_DIRECT        0x100000 /* direct disk access hint */
+#elif defined(TARGET_MIPS)
+#define TARGET_O_ACCMODE       0x0003
+#define TARGET_O_RDONLY        0x0000
+#define TARGET_O_WRONLY        0x0001
+#define TARGET_O_RDWR          0x0002
+#define TARGET_O_APPEND        0x0008
+#define TARGET_O_SYNC          0x0010
+#define TARGET_O_NONBLOCK      0x0080
+#define TARGET_O_CREAT         0x0100  /* not fcntl */
+#define TARGET_O_TRUNC         0x0200  /* not fcntl */
+#define TARGET_O_EXCL          0x0400  /* not fcntl */
+#define TARGET_O_NOCTTY        0x0800  /* not fcntl */
+#define TARGET_FASYNC          0x1000  /* fcntl, for BSD compatibility */
+#define TARGET_O_LARGEFILE     0x2000  /* allow large file opens */
+#define TARGET_O_DIRECT        0x8000  /* direct disk access hint */
+#define TARGET_O_DIRECTORY     0x10000 /* must be a directory */
+#define TARGET_O_NOFOLLOW      0x20000 /* don't follow links */
+#define TARGET_O_NOATIME       0x40000
+#define TARGET_O_NDELAY        TARGET_O_NONBLOCK
 #else
 #define TARGET_O_ACCMODE          0003
 #define TARGET_O_RDONLY             00
@@ -1061,7 +1275,7 @@ struct target_stat64 {
 #define TARGET_O_TRUNC           01000 /* not fcntl */
 #define TARGET_O_APPEND          02000
 #define TARGET_O_NONBLOCK        04000
-#define TARGET_O_NDELAY        O_NONBLOCK
+#define TARGET_O_NDELAY        TARGET_O_NONBLOCK
 #define TARGET_O_SYNC           010000
 #define TARGET_FASYNC           020000 /* fcntl, for BSD compatibility */
 #define TARGET_O_DIRECT         040000 /* direct disk access hint */
diff --git a/qemu/m68k-dis.c b/qemu/m68k-dis.c
new file mode 100644 (file)
index 0000000..dd19558
--- /dev/null
@@ -0,0 +1,5051 @@
+/* This file is composed of several different files from the upstream
+   sourceware.org CVS.  Original file boundaries marked with **** */
+
+#include <string.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "dis-asm.h"
+
+/* **** foatformat.h from sourceware.org CVS 2005-08-14.  */
+/* IEEE floating point support declarations, for GDB, the GNU Debugger.
+   Copyright 1991, 1994, 1995, 1997, 2000, 2003 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+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.  */
+
+#if !defined (FLOATFORMAT_H)
+#define FLOATFORMAT_H 1
+
+/*#include "ansidecl.h" */
+
+/* A floatformat consists of a sign bit, an exponent and a mantissa.  Once the
+   bytes are concatenated according to the byteorder flag, then each of those
+   fields is contiguous.  We number the bits with 0 being the most significant
+   (i.e. BITS_BIG_ENDIAN type numbering), and specify which bits each field
+   contains with the *_start and *_len fields.  */
+
+/* What is the order of the bytes. */
+
+enum floatformat_byteorders {
+
+  /* Standard little endian byte order.
+     EX: 1.2345678e10 => 00 00 80 c5 e0 fe 06 42 */
+
+  floatformat_little,
+
+  /* Standard big endian byte order.
+     EX: 1.2345678e10 => 42 06 fe e0 c5 80 00 00 */
+
+  floatformat_big,
+
+  /* Little endian byte order but big endian word order.
+     EX: 1.2345678e10 => e0 fe 06 42 00 00 80 c5 */
+
+  floatformat_littlebyte_bigword
+
+};
+
+enum floatformat_intbit { floatformat_intbit_yes, floatformat_intbit_no };
+
+struct floatformat
+{
+  enum floatformat_byteorders byteorder;
+  unsigned int totalsize;      /* Total size of number in bits */
+
+  /* Sign bit is always one bit long.  1 means negative, 0 means positive.  */
+  unsigned int sign_start;
+
+  unsigned int exp_start;
+  unsigned int exp_len;
+  /* Bias added to a "true" exponent to form the biased exponent.  It
+     is intentionally signed as, otherwize, -exp_bias can turn into a
+     very large number (e.g., given the exp_bias of 0x3fff and a 64
+     bit long, the equation (long)(1 - exp_bias) evaluates to
+     4294950914) instead of -16382).  */
+  int exp_bias;
+  /* Exponent value which indicates NaN.  This is the actual value stored in
+     the float, not adjusted by the exp_bias.  This usually consists of all
+     one bits.  */
+  unsigned int exp_nan;
+
+  unsigned int man_start;
+  unsigned int man_len;
+
+  /* Is the integer bit explicit or implicit?  */
+  enum floatformat_intbit intbit;
+
+  /* Internal name for debugging. */
+  const char *name;
+
+  /* Validator method.  */
+  int (*is_valid) (const struct floatformat *fmt, const char *from);
+};
+
+/* floatformats for IEEE single and double, big and little endian.  */
+
+extern const struct floatformat floatformat_ieee_single_big;
+extern const struct floatformat floatformat_ieee_single_little;
+extern const struct floatformat floatformat_ieee_double_big;
+extern const struct floatformat floatformat_ieee_double_little;
+
+/* floatformat for ARM IEEE double, little endian bytes and big endian words */
+
+extern const struct floatformat floatformat_ieee_double_littlebyte_bigword;
+
+/* floatformats for various extendeds.  */
+
+extern const struct floatformat floatformat_i387_ext;
+extern const struct floatformat floatformat_m68881_ext;
+extern const struct floatformat floatformat_i960_ext;
+extern const struct floatformat floatformat_m88110_ext;
+extern const struct floatformat floatformat_m88110_harris_ext;
+extern const struct floatformat floatformat_arm_ext_big;
+extern const struct floatformat floatformat_arm_ext_littlebyte_bigword;
+/* IA-64 Floating Point register spilt into memory.  */
+extern const struct floatformat floatformat_ia64_spill_big;
+extern const struct floatformat floatformat_ia64_spill_little;
+extern const struct floatformat floatformat_ia64_quad_big;
+extern const struct floatformat floatformat_ia64_quad_little;
+
+/* Convert from FMT to a double.
+   FROM is the address of the extended float.
+   Store the double in *TO.  */
+
+extern void
+floatformat_to_double (const struct floatformat *, const char *, double *);
+
+/* The converse: convert the double *FROM to FMT
+   and store where TO points.  */
+
+extern void
+floatformat_from_double (const struct floatformat *, const double *, char *);
+
+/* Return non-zero iff the data at FROM is a valid number in format FMT.  */
+
+extern int
+floatformat_is_valid (const struct floatformat *fmt, const char *from);
+
+#endif /* defined (FLOATFORMAT_H) */
+/* **** End of floatformat.h */
+/* **** m68k-dis.h from sourceware.org CVS 2005-08-14.  */
+/* Opcode table header for m680[01234]0/m6888[12]/m68851.
+   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2001,
+   2003, 2004 Free Software Foundation, Inc.
+
+   This file is part of GDB, GAS, and the GNU binutils.
+
+   GDB, GAS, and the GNU binutils are free software; you can redistribute
+   them and/or modify them under the terms of the GNU General Public
+   License as published by the Free Software Foundation; either version
+   1, or (at your option) any later version.
+
+   GDB, GAS, and the GNU binutils are distributed in the hope that they
+   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.  */
+
+/* These are used as bit flags for the arch field in the m68k_opcode
+   structure.  */
+#define        _m68k_undef  0
+#define        m68000   0x001
+#define        m68008   m68000 /* Synonym for -m68000.  otherwise unused.  */
+#define        m68010   0x002
+#define        m68020   0x004
+#define        m68030   0x008
+#define m68ec030 m68030 /* Similar enough to -m68030 to ignore differences;
+                          gas will deal with the few differences.  */
+#define        m68040   0x010
+/* There is no 68050.  */
+#define m68060   0x020
+#define        m68881   0x040
+#define        m68882   m68881 /* Synonym for -m68881.  otherwise unused.  */
+#define        m68851   0x080
+#define cpu32   0x100          /* e.g., 68332 */
+
+#define mcfmac   0x200         /* ColdFire MAC. */
+#define mcfemac  0x400         /* ColdFire EMAC. */
+#define cfloat   0x800         /* ColdFire FPU.  */
+#define mcfhwdiv 0x1000                /* ColdFire hardware divide.  */
+
+#define mcfisa_a 0x2000                /* ColdFire ISA_A.  */
+#define mcfisa_aa 0x4000       /* ColdFire ISA_A+.  */
+#define mcfisa_b 0x8000                /* ColdFire ISA_B.  */
+#define mcfusp   0x10000       /* ColdFire USP instructions.  */
+
+#define mcf5200  0x20000
+#define mcf5206e 0x40000
+#define mcf521x  0x80000
+#define mcf5249  0x100000
+#define mcf528x  0x200000
+#define mcf5307  0x400000
+#define mcf5407  0x800000
+#define mcf5470  0x1000000
+#define mcf5480  0x2000000
+
+ /* Handy aliases.  */
+#define        m68040up   (m68040 | m68060)
+#define        m68030up   (m68030 | m68040up)
+#define        m68020up   (m68020 | m68030up)
+#define        m68010up   (m68010 | cpu32 | m68020up)
+#define        m68000up   (m68000 | m68010up)
+
+#define        mfloat  (m68881 | m68882 | m68040 | m68060)
+#define        mmmu    (m68851 | m68030 | m68040 | m68060)
+
+/* The structure used to hold information for an opcode.  */
+
+struct m68k_opcode
+{
+  /* The opcode name.  */
+  const char *name;
+  /* The pseudo-size of the instruction(in bytes).  Used to determine
+     number of bytes necessary to disassemble the instruction.  */
+  unsigned int size;
+  /* The opcode itself.  */
+  unsigned long opcode;
+  /* The mask used by the disassembler.  */
+  unsigned long match;
+  /* The arguments.  */
+  const char *args;
+  /* The architectures which support this opcode.  */
+  unsigned int arch;
+};
+
+/* The structure used to hold information for an opcode alias.  */
+
+struct m68k_opcode_alias
+{
+  /* The alias name.  */
+  const char *alias;
+  /* The instruction for which this is an alias.  */
+  const char *primary;
+};
+
+/* We store four bytes of opcode for all opcodes because that is the
+   most any of them need.  The actual length of an instruction is
+   always at least 2 bytes, and is as much longer as necessary to hold
+   the operands it has.
+
+   The match field is a mask saying which bits must match particular
+   opcode in order for an instruction to be an instance of that
+   opcode.
+
+   The args field is a string containing two characters for each
+   operand of the instruction.  The first specifies the kind of
+   operand; the second, the place it is stored.  */
+
+/* Kinds of operands:
+   Characters used: AaBbCcDdEeFfGgHIiJkLlMmnOopQqRrSsTtU VvWwXxYyZz01234|*~%;@!&$?/<>#^+-
+
+   D  data register only.  Stored as 3 bits.
+   A  address register only.  Stored as 3 bits.
+   a  address register indirect only.  Stored as 3 bits.
+   R  either kind of register.  Stored as 4 bits.
+   r  either kind of register indirect only.  Stored as 4 bits.
+      At the moment, used only for cas2 instruction.
+   F  floating point coprocessor register only.   Stored as 3 bits.
+   O  an offset (or width): immediate data 0-31 or data register.
+      Stored as 6 bits in special format for BF... insns.
+   +  autoincrement only.  Stored as 3 bits (number of the address register).
+   -  autodecrement only.  Stored as 3 bits (number of the address register).
+   Q  quick immediate data.  Stored as 3 bits.
+      This matches an immediate operand only when value is in range 1 .. 8.
+   M  moveq immediate data.  Stored as 8 bits.
+      This matches an immediate operand only when value is in range -128..127
+   T  trap vector immediate data.  Stored as 4 bits.
+
+   k  K-factor for fmove.p instruction.   Stored as a 7-bit constant or
+      a three bit register offset, depending on the field type.
+
+   #  immediate data.  Stored in special places (b, w or l)
+      which say how many bits to store.
+   ^  immediate data for floating point instructions.   Special places
+      are offset by 2 bytes from '#'...
+   B  pc-relative address, converted to an offset
+      that is treated as immediate data.
+   d  displacement and register.  Stores the register as 3 bits
+      and stores the displacement in the entire second word.
+
+   C  the CCR.  No need to store it; this is just for filtering validity.
+   S  the SR.  No need to store, just as with CCR.
+   U  the USP.  No need to store, just as with CCR.
+   E  the MAC ACC.  No need to store, just as with CCR.
+   e  the EMAC ACC[0123].
+   G  the MAC/EMAC MACSR.  No need to store, just as with CCR.
+   g  the EMAC ACCEXT{01,23}.
+   H  the MASK.  No need to store, just as with CCR.
+   i  the MAC/EMAC scale factor.
+
+   I  Coprocessor ID.   Not printed if 1.   The Coprocessor ID is always
+      extracted from the 'd' field of word one, which means that an extended
+      coprocessor opcode can be skipped using the 'i' place, if needed.
+
+   s  System Control register for the floating point coprocessor.
+
+   J  Misc register for movec instruction, stored in 'j' format.
+       Possible values:
+       0x000   SFC     Source Function Code reg        [60, 40, 30, 20, 10]
+       0x001   DFC     Data Function Code reg          [60, 40, 30, 20, 10]
+       0x002   CACR    Cache Control Register          [60, 40, 30, 20, mcf]
+       0x003   TC      MMU Translation Control         [60, 40]
+       0x004   ITT0    Instruction Transparent
+                               Translation reg 0       [60, 40]
+       0x005   ITT1    Instruction Transparent
+                               Translation reg 1       [60, 40]
+       0x006   DTT0    Data Transparent
+                               Translation reg 0       [60, 40]
+       0x007   DTT1    Data Transparent
+                               Translation reg 1       [60, 40]
+       0x008   BUSCR   Bus Control Register            [60]
+       0x800   USP     User Stack Pointer              [60, 40, 30, 20, 10]
+        0x801   VBR     Vector Base reg                 [60, 40, 30, 20, 10, mcf]
+       0x802   CAAR    Cache Address Register          [        30, 20]
+       0x803   MSP     Master Stack Pointer            [    40, 30, 20]
+       0x804   ISP     Interrupt Stack Pointer         [    40, 30, 20]
+       0x805   MMUSR   MMU Status reg                  [    40]
+       0x806   URP     User Root Pointer               [60, 40]
+       0x807   SRP     Supervisor Root Pointer         [60, 40]
+       0x808   PCR     Processor Configuration reg     [60]
+       0xC00   ROMBAR  ROM Base Address Register       [520X]
+       0xC04   RAMBAR0 RAM Base Address Register 0     [520X]
+       0xC05   RAMBAR1 RAM Base Address Register 0     [520X]
+       0xC0F   MBAR0   RAM Base Address Register 0     [520X]
+        0xC04   FLASHBAR FLASH Base Address Register    [mcf528x]
+        0xC05   RAMBAR  Static RAM Base Address Register [mcf528x]
+
+    L  Register list of the type d0-d7/a0-a7 etc.
+       (New!  Improved!  Can also hold fp0-fp7, as well!)
+       The assembler tries to see if the registers match the insn by
+       looking at where the insn wants them stored.
+
+    l  Register list like L, but with all the bits reversed.
+       Used for going the other way. . .
+
+    c  cache identifier which may be "nc" for no cache, "ic"
+       for instruction cache, "dc" for data cache, or "bc"
+       for both caches.  Used in cinv and cpush.  Always
+       stored in position "d".
+
+    u  Any register, with ``upper'' or ``lower'' specification.  Used
+       in the mac instructions with size word.
+
+ The remainder are all stored as 6 bits using an address mode and a
+ register number; they differ in which addressing modes they match.
+
+   *  all                                      (modes 0-6,7.0-4)
+   ~  alterable memory                         (modes 2-6,7.0,7.1)
+                                               (not 0,1,7.2-4)
+   %  alterable                                        (modes 0-6,7.0,7.1)
+                                               (not 7.2-4)
+   ;  data                                     (modes 0,2-6,7.0-4)
+                                               (not 1)
+   @  data, but not immediate                  (modes 0,2-6,7.0-3)
+                                               (not 1,7.4)
+   !  control                                  (modes 2,5,6,7.0-3)
+                                               (not 0,1,3,4,7.4)
+   &  alterable control                                (modes 2,5,6,7.0,7.1)
+                                               (not 0,1,3,4,7.2-4)
+   $  alterable data                           (modes 0,2-6,7.0,7.1)
+                                               (not 1,7.2-4)
+   ?  alterable control, or data register      (modes 0,2,5,6,7.0,7.1)
+                                               (not 1,3,4,7.2-4)
+   /  control, or data register                        (modes 0,2,5,6,7.0-3)
+                                               (not 1,3,4,7.4)
+   >  *save operands                           (modes 2,4,5,6,7.0,7.1)
+                                               (not 0,1,3,7.2-4)
+   <  *restore operands                                (modes 2,3,5,6,7.0-3)
+                                               (not 0,1,4,7.4)
+
+   coldfire move operands:
+   m                                           (modes 0-4)
+   n                                           (modes 5,7.2)
+   o                                           (modes 6,7.0,7.1,7.3,7.4)
+   p                                           (modes 0-5)
+
+   coldfire bset/bclr/btst/mulsl/mulul operands:
+   q                                           (modes 0,2-5)
+   v                                           (modes 0,2-5,7.0,7.1)
+   b                                            (modes 0,2-5,7.2)
+   w                                            (modes 2-5,7.2)
+   y                                           (modes 2,5)
+   z                                           (modes 2,5,7.2)
+   x  mov3q immediate operand.
+   4                                           (modes 2,3,4,5)
+  */
+
+/* For the 68851:  */
+/* I didn't use much imagination in choosing the
+   following codes, so many of them aren't very
+   mnemonic. -rab
+
+   0  32 bit pmmu register
+       Possible values:
+       000     TC      Translation Control Register (68030, 68851)
+
+   1  16 bit pmmu register
+       111     AC      Access Control (68851)
+
+   2  8 bit pmmu register
+       100     CAL     Current Access Level (68851)
+       101     VAL     Validate Access Level (68851)
+       110     SCC     Stack Change Control (68851)
+
+   3  68030-only pmmu registers (32 bit)
+       010     TT0     Transparent Translation reg 0
+                       (aka Access Control reg 0 -- AC0 -- on 68ec030)
+       011     TT1     Transparent Translation reg 1
+                       (aka Access Control reg 1 -- AC1 -- on 68ec030)
+
+   W  wide pmmu registers
+       Possible values:
+       001     DRP     Dma Root Pointer (68851)
+       010     SRP     Supervisor Root Pointer (68030, 68851)
+       011     CRP     Cpu Root Pointer (68030, 68851)
+
+   f   function code register (68030, 68851)
+       0       SFC
+       1       DFC
+
+   V   VAL register only (68851)
+
+   X   BADx, BACx (16 bit)
+       100     BAD     Breakpoint Acknowledge Data (68851)
+       101     BAC     Breakpoint Acknowledge Control (68851)
+
+   Y   PSR (68851) (MMUSR on 68030) (ACUSR on 68ec030)
+   Z   PCSR (68851)
+
+   |   memory          (modes 2-6, 7.*)
+
+   t  address test level (68030 only)
+      Stored as 3 bits, range 0-7.
+      Also used for breakpoint instruction now.
+
+*/
+
+/* Places to put an operand, for non-general operands:
+   Characters used: BbCcDdFfGgHhIijkLlMmNnostWw123456789/
+
+   s  source, low bits of first word.
+   d  dest, shifted 9 in first word
+   1  second word, shifted 12
+   2  second word, shifted 6
+   3  second word, shifted 0
+   4  third word, shifted 12
+   5  third word, shifted 6
+   6  third word, shifted 0
+   7  second word, shifted 7
+   8  second word, shifted 10
+   9  second word, shifted 5
+   D  store in both place 1 and place 3; for divul and divsl.
+   B  first word, low byte, for branch displacements
+   W  second word (entire), for branch displacements
+   L  second and third words (entire), for branch displacements
+      (also overloaded for move16)
+   b  second word, low byte
+   w  second word (entire) [variable word/long branch offset for dbra]
+   W  second word (entire) (must be signed 16 bit value)
+   l  second and third word (entire)
+   g  variable branch offset for bra and similar instructions.
+      The place to store depends on the magnitude of offset.
+   t  store in both place 7 and place 8; for floating point operations
+   c  branch offset for cpBcc operations.
+      The place to store is word two if bit six of word one is zero,
+      and words two and three if bit six of word one is one.
+   i  Increment by two, to skip over coprocessor extended operands.   Only
+      works with the 'I' format.
+   k  Dynamic K-factor field.   Bits 6-4 of word 2, used as a register number.
+      Also used for dynamic fmovem instruction.
+   C  floating point coprocessor constant - 7 bits.  Also used for static
+      K-factors...
+   j  Movec register #, stored in 12 low bits of second word.
+   m  For M[S]ACx; 4 bits split with MSB shifted 6 bits in first word
+      and remaining 3 bits of register shifted 9 bits in first word.
+      Indicate upper/lower in 1 bit shifted 7 bits in second word.
+      Use with `R' or `u' format.
+   n  `m' withouth upper/lower indication. (For M[S]ACx; 4 bits split
+      with MSB shifted 6 bits in first word and remaining 3 bits of
+      register shifted 9 bits in first word.  No upper/lower
+      indication is done.)  Use with `R' or `u' format.
+   o  For M[S]ACw; 4 bits shifted 12 in second word (like `1').
+      Indicate upper/lower in 1 bit shifted 7 bits in second word.
+      Use with `R' or `u' format.
+   M  For M[S]ACw; 4 bits in low bits of first word.  Indicate
+      upper/lower in 1 bit shifted 6 bits in second word.  Use with
+      `R' or `u' format.
+   N  For M[S]ACw; 4 bits in low bits of second word.  Indicate
+      upper/lower in 1 bit shifted 6 bits in second word.  Use with
+      `R' or `u' format.
+   h  shift indicator (scale factor), 1 bit shifted 10 in second word
+
+ Places to put operand, for general operands:
+   d  destination, shifted 6 bits in first word
+   b  source, at low bit of first word, and immediate uses one byte
+   w  source, at low bit of first word, and immediate uses two bytes
+   l  source, at low bit of first word, and immediate uses four bytes
+   s  source, at low bit of first word.
+      Used sometimes in contexts where immediate is not allowed anyway.
+   f  single precision float, low bit of 1st word, immediate uses 4 bytes
+   F  double precision float, low bit of 1st word, immediate uses 8 bytes
+   x  extended precision float, low bit of 1st word, immediate uses 12 bytes
+   p  packed float, low bit of 1st word, immediate uses 12 bytes
+   G  EMAC accumulator, load  (bit 4 2nd word, !bit8 first word)
+   H  EMAC accumulator, non load  (bit 4 2nd word, bit 8 first word)
+   F  EMAC ACCx
+   f  EMAC ACCy
+   I  MAC/EMAC scale factor
+   /  Like 's', but set 2nd word, bit 5 if trailing_ampersand set
+   ]  first word, bit 10
+*/
+
+extern const struct m68k_opcode m68k_opcodes[];
+extern const struct m68k_opcode_alias m68k_opcode_aliases[];
+
+extern const int m68k_numopcodes, m68k_numaliases;
+
+/* **** End of m68k-opcode.h */
+/* **** m68k-dis.c from sourceware.org CVS 2005-08-14.  */
+/* Print Motorola 68k instructions.
+   Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+   1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Free Software Foundation, Inc.
+
+   This file 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.  */
+
+/* Local function prototypes.  */
+
+const char * const fpcr_names[] =
+{
+  "", "%fpiar", "%fpsr", "%fpiar/%fpsr", "%fpcr",
+  "%fpiar/%fpcr", "%fpsr/%fpcr", "%fpiar/%fpsr/%fpcr"
+};
+
+static char *const reg_names[] =
+{
+  "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
+  "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp",
+  "%ps", "%pc"
+};
+
+/* Name of register halves for MAC/EMAC.
+   Seperate from reg_names since 'spu', 'fpl' look weird.  */
+static char *const reg_half_names[] =
+{
+  "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
+  "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
+  "%ps", "%pc"
+};
+
+/* Sign-extend an (unsigned char).  */
+#if __STDC__ == 1
+#define COERCE_SIGNED_CHAR(ch) ((signed char) (ch))
+#else
+#define COERCE_SIGNED_CHAR(ch) ((int) (((ch) ^ 0x80) & 0xFF) - 128)
+#endif
+
+/* Get a 1 byte signed integer.  */
+#define NEXTBYTE(p)  (p += 2, FETCH_DATA (info, p), COERCE_SIGNED_CHAR(p[-1]))
+
+/* Get a 2 byte signed integer.  */
+#define COERCE16(x) ((int) (((x) ^ 0x8000) - 0x8000))
+#define NEXTWORD(p)  \
+  (p += 2, FETCH_DATA (info, p), \
+   COERCE16 ((p[-2] << 8) + p[-1]))
+
+/* Get a 4 byte signed integer.  */
+#define COERCE32(x) ((bfd_signed_vma) ((x) ^ 0x80000000) - 0x80000000)
+#define NEXTLONG(p)  \
+  (p += 4, FETCH_DATA (info, p), \
+   (COERCE32 ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])))
+
+/* Get a 4 byte unsigned integer.  */
+#define NEXTULONG(p)  \
+  (p += 4, FETCH_DATA (info, p), \
+   (unsigned int) ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]))
+
+/* Get a single precision float.  */
+#define NEXTSINGLE(val, p) \
+  (p += 4, FETCH_DATA (info, p), \
+   floatformat_to_double (&floatformat_ieee_single_big, (char *) p - 4, &val))
+
+/* Get a double precision float.  */
+#define NEXTDOUBLE(val, p) \
+  (p += 8, FETCH_DATA (info, p), \
+   floatformat_to_double (&floatformat_ieee_double_big, (char *) p - 8, &val))
+
+/* Get an extended precision float.  */
+#define NEXTEXTEND(val, p) \
+  (p += 12, FETCH_DATA (info, p), \
+   floatformat_to_double (&floatformat_m68881_ext, (char *) p - 12, &val))
+
+/* Need a function to convert from packed to double
+   precision.   Actually, it's easier to print a
+   packed number than a double anyway, so maybe
+   there should be a special case to handle this... */
+#define NEXTPACKED(p) \
+  (p += 12, FETCH_DATA (info, p), 0.0)
+\f
+/* Maximum length of an instruction.  */
+#define MAXLEN 22
+
+#include <setjmp.h>
+
+struct private
+{
+  /* Points to first byte not fetched.  */
+  bfd_byte *max_fetched;
+  bfd_byte the_buffer[MAXLEN];
+  bfd_vma insn_start;
+  jmp_buf bailout;
+};
+
+/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
+   to ADDR (exclusive) are valid.  Returns 1 for success, longjmps
+   on error.  */
+#define FETCH_DATA(info, addr) \
+  ((addr) <= ((struct private *) (info->private_data))->max_fetched \
+   ? 1 : fetch_data ((info), (addr)))
+
+static int
+fetch_data (struct disassemble_info *info, bfd_byte *addr)
+{
+  int status;
+  struct private *priv = (struct private *)info->private_data;
+  bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
+
+  status = (*info->read_memory_func) (start,
+                                     priv->max_fetched,
+                                     addr - priv->max_fetched,
+                                     info);
+  if (status != 0)
+    {
+      (*info->memory_error_func) (status, start, info);
+      longjmp (priv->bailout, 1);
+    }
+  else
+    priv->max_fetched = addr;
+  return 1;
+}
+\f
+/* This function is used to print to the bit-bucket.  */
+static int
+dummy_printer (FILE *file ATTRIBUTE_UNUSED,
+              const char *format ATTRIBUTE_UNUSED,
+              ...)
+{
+  return 0;
+}
+
+static void
+dummy_print_address (bfd_vma vma ATTRIBUTE_UNUSED,
+                    struct disassemble_info *info ATTRIBUTE_UNUSED)
+{
+}
+
+/* Fetch BITS bits from a position in the instruction specified by CODE.
+   CODE is a "place to put an argument", or 'x' for a destination
+   that is a general address (mode and register).
+   BUFFER contains the instruction.  */
+
+static int
+fetch_arg (unsigned char *buffer,
+          int code,
+          int bits,
+          disassemble_info *info)
+{
+  int val = 0;
+
+  switch (code)
+    {
+    case '/': /* MAC/EMAC mask bit.  */
+      val = buffer[3] >> 5;
+      break;
+
+    case 'G': /* EMAC ACC load.  */
+      val = ((buffer[3] >> 3) & 0x2) | ((~buffer[1] >> 7) & 0x1);
+      break;
+
+    case 'H': /* EMAC ACC !load.  */
+      val = ((buffer[3] >> 3) & 0x2) | ((buffer[1] >> 7) & 0x1);
+      break;
+
+    case ']': /* EMAC ACCEXT bit.  */
+      val = buffer[0] >> 2;
+      break;
+
+    case 'I': /* MAC/EMAC scale factor.  */
+      val = buffer[2] >> 1;
+      break;
+
+    case 'F': /* EMAC ACCx.  */
+      val = buffer[0] >> 1;
+      break;
+
+    case 'f':
+      val = buffer[1];
+      break;
+
+    case 's':
+      val = buffer[1];
+      break;
+
+    case 'd':                  /* Destination, for register or quick.  */
+      val = (buffer[0] << 8) + buffer[1];
+      val >>= 9;
+      break;
+
+    case 'x':                  /* Destination, for general arg.  */
+      val = (buffer[0] << 8) + buffer[1];
+      val >>= 6;
+      break;
+
+    case 'k':
+      FETCH_DATA (info, buffer + 3);
+      val = (buffer[3] >> 4);
+      break;
+
+    case 'C':
+      FETCH_DATA (info, buffer + 3);
+      val = buffer[3];
+      break;
+
+    case '1':
+      FETCH_DATA (info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 12;
+      break;
+
+    case '2':
+      FETCH_DATA (info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 6;
+      break;
+
+    case '3':
+    case 'j':
+      FETCH_DATA (info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      break;
+
+    case '4':
+      FETCH_DATA (info, buffer + 5);
+      val = (buffer[4] << 8) + buffer[5];
+      val >>= 12;
+      break;
+
+    case '5':
+      FETCH_DATA (info, buffer + 5);
+      val = (buffer[4] << 8) + buffer[5];
+      val >>= 6;
+      break;
+
+    case '6':
+      FETCH_DATA (info, buffer + 5);
+      val = (buffer[4] << 8) + buffer[5];
+      break;
+
+    case '7':
+      FETCH_DATA (info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 7;
+      break;
+
+    case '8':
+      FETCH_DATA (info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 10;
+      break;
+
+    case '9':
+      FETCH_DATA (info, buffer + 3);
+      val = (buffer[2] << 8) + buffer[3];
+      val >>= 5;
+      break;
+
+    case 'e':
+      val = (buffer[1] >> 6);
+      break;
+
+    case 'm':
+      val = (buffer[1] & 0x40 ? 0x8 : 0)
+       | ((buffer[0] >> 1) & 0x7)
+       | (buffer[3] & 0x80 ? 0x10 : 0);
+      break;
+
+    case 'n':
+      val = (buffer[1] & 0x40 ? 0x8 : 0) | ((buffer[0] >> 1) & 0x7);
+      break;
+
+    case 'o':
+      val = (buffer[2] >> 4) | (buffer[3] & 0x80 ? 0x10 : 0);
+      break;
+
+    case 'M':
+      val = (buffer[1] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0);
+      break;
+
+    case 'N':
+      val = (buffer[3] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0);
+      break;
+
+    case 'h':
+      val = buffer[2] >> 2;
+      break;
+
+    default:
+      abort ();
+    }
+
+  switch (bits)
+    {
+    case 1:
+      return val & 1;
+    case 2:
+      return val & 3;
+    case 3:
+      return val & 7;
+    case 4:
+      return val & 017;
+    case 5:
+      return val & 037;
+    case 6:
+      return val & 077;
+    case 7:
+      return val & 0177;
+    case 8:
+      return val & 0377;
+    case 12:
+      return val & 07777;
+    default:
+      abort ();
+    }
+}
+
+/* Check if an EA is valid for a particular code.  This is required
+   for the EMAC instructions since the type of source address determines
+   if it is a EMAC-load instruciton if the EA is mode 2-5, otherwise it
+   is a non-load EMAC instruction and the bits mean register Ry.
+   A similar case exists for the movem instructions where the register
+   mask is interpreted differently for different EAs.  */
+
+static bfd_boolean
+m68k_valid_ea (char code, int val)
+{
+  int mode, mask;
+#define M(n0,n1,n2,n3,n4,n5,n6,n70,n71,n72,n73,n74) \
+  (n0 | n1 << 1 | n2 << 2 | n3 << 3 | n4 << 4 | n5 << 5 | n6 << 6 \
+   | n70 << 7 | n71 << 8 | n72 << 9 | n73 << 10 | n74 << 11)
+
+  switch (code)
+    {
+    case '*':
+      mask = M (1,1,1,1,1,1,1,1,1,1,1,1);
+      break;
+    case '~':
+      mask = M (0,0,1,1,1,1,1,1,1,0,0,0);
+      break;
+    case '%':
+      mask = M (1,1,1,1,1,1,1,1,1,0,0,0);
+      break;
+    case ';':
+      mask = M (1,0,1,1,1,1,1,1,1,1,1,1);
+      break;
+    case '@':
+      mask = M (1,0,1,1,1,1,1,1,1,1,1,0);
+      break;
+    case '!':
+      mask = M (0,0,1,0,0,1,1,1,1,1,1,0);
+      break;
+    case '&':
+      mask = M (0,0,1,0,0,1,1,1,1,0,0,0);
+      break;
+    case '$':
+      mask = M (1,0,1,1,1,1,1,1,1,0,0,0);
+      break;
+    case '?':
+      mask = M (1,0,1,0,0,1,1,1,1,0,0,0);
+      break;
+    case '/':
+      mask = M (1,0,1,0,0,1,1,1,1,1,1,0);
+      break;
+    case '|':
+      mask = M (0,0,1,0,0,1,1,1,1,1,1,0);
+      break;
+    case '>':
+      mask = M (0,0,1,0,1,1,1,1,1,0,0,0);
+      break;
+    case '<':
+      mask = M (0,0,1,1,0,1,1,1,1,1,1,0);
+      break;
+    case 'm':
+      mask = M (1,1,1,1,1,0,0,0,0,0,0,0);
+      break;
+    case 'n':
+      mask = M (0,0,0,0,0,1,0,0,0,1,0,0);
+      break;
+    case 'o':
+      mask = M (0,0,0,0,0,0,1,1,1,0,1,1);
+      break;
+    case 'p':
+      mask = M (1,1,1,1,1,1,0,0,0,0,0,0);
+      break;
+    case 'q':
+      mask = M (1,0,1,1,1,1,0,0,0,0,0,0);
+      break;
+    case 'v':
+      mask = M (1,0,1,1,1,1,0,1,1,0,0,0);
+      break;
+    case 'b':
+      mask = M (1,0,1,1,1,1,0,0,0,1,0,0);
+      break;
+    case 'w':
+      mask = M (0,0,1,1,1,1,0,0,0,1,0,0);
+      break;
+    case 'y':
+      mask = M (0,0,1,0,0,1,0,0,0,0,0,0);
+      break;
+    case 'z':
+      mask = M (0,0,1,0,0,1,0,0,0,1,0,0);
+      break;
+    case '4':
+      mask = M (0,0,1,1,1,1,0,0,0,0,0,0);
+      break;
+    default:
+      abort ();
+    }
+#undef M
+
+  mode = (val >> 3) & 7;
+  if (mode == 7)
+    mode += val & 7;
+  return (mask & (1 << mode)) != 0;
+}
+
+/* Print a base register REGNO and displacement DISP, on INFO->STREAM.
+   REGNO = -1 for pc, -2 for none (suppressed).  */
+
+static void
+print_base (int regno, bfd_vma disp, disassemble_info *info)
+{
+  if (regno == -1)
+    {
+      (*info->fprintf_func) (info->stream, "%%pc@(");
+      (*info->print_address_func) (disp, info);
+    }
+  else
+    {
+      char buf[50];
+
+      if (regno == -2)
+       (*info->fprintf_func) (info->stream, "@(");
+      else if (regno == -3)
+       (*info->fprintf_func) (info->stream, "%%zpc@(");
+      else
+       (*info->fprintf_func) (info->stream, "%s@(", reg_names[regno]);
+
+      sprintf_vma (buf, disp);
+      (*info->fprintf_func) (info->stream, "%s", buf);
+    }
+}
+
+/* Print an indexed argument.  The base register is BASEREG (-1 for pc).
+   P points to extension word, in buffer.
+   ADDR is the nominal core address of that extension word.  */
+
+static unsigned char *
+print_indexed (int basereg,
+              unsigned char *p,
+              bfd_vma addr,
+              disassemble_info *info)
+{
+  int word;
+  static char *const scales[] = { "", ":2", ":4", ":8" };
+  bfd_vma base_disp;
+  bfd_vma outer_disp;
+  char buf[40];
+  char vmabuf[50];
+
+  word = NEXTWORD (p);
+
+  /* Generate the text for the index register.
+     Where this will be output is not yet determined.  */
+  sprintf (buf, "%s:%c%s",
+          reg_names[(word >> 12) & 0xf],
+          (word & 0x800) ? 'l' : 'w',
+          scales[(word >> 9) & 3]);
+
+  /* Handle the 68000 style of indexing.  */
+
+  if ((word & 0x100) == 0)
+    {
+      base_disp = word & 0xff;
+      if ((base_disp & 0x80) != 0)
+       base_disp -= 0x100;
+      if (basereg == -1)
+       base_disp += addr;
+      print_base (basereg, base_disp, info);
+      (*info->fprintf_func) (info->stream, ",%s)", buf);
+      return p;
+    }
+
+  /* Handle the generalized kind.  */
+  /* First, compute the displacement to add to the base register.  */
+  if (word & 0200)
+    {
+      if (basereg == -1)
+       basereg = -3;
+      else
+       basereg = -2;
+    }
+  if (word & 0100)
+    buf[0] = '\0';
+  base_disp = 0;
+  switch ((word >> 4) & 3)
+    {
+    case 2:
+      base_disp = NEXTWORD (p);
+      break;
+    case 3:
+      base_disp = NEXTLONG (p);
+    }
+  if (basereg == -1)
+    base_disp += addr;
+
+  /* Handle single-level case (not indirect).  */
+  if ((word & 7) == 0)
+    {
+      print_base (basereg, base_disp, info);
+      if (buf[0] != '\0')
+       (*info->fprintf_func) (info->stream, ",%s", buf);
+      (*info->fprintf_func) (info->stream, ")");
+      return p;
+    }
+
+  /* Two level.  Compute displacement to add after indirection.  */
+  outer_disp = 0;
+  switch (word & 3)
+    {
+    case 2:
+      outer_disp = NEXTWORD (p);
+      break;
+    case 3:
+      outer_disp = NEXTLONG (p);
+    }
+
+  print_base (basereg, base_disp, info);
+  if ((word & 4) == 0 && buf[0] != '\0')
+    {
+      (*info->fprintf_func) (info->stream, ",%s", buf);
+      buf[0] = '\0';
+    }
+  sprintf_vma (vmabuf, outer_disp);
+  (*info->fprintf_func) (info->stream, ")@(%s", vmabuf);
+  if (buf[0] != '\0')
+    (*info->fprintf_func) (info->stream, ",%s", buf);
+  (*info->fprintf_func) (info->stream, ")");
+
+  return p;
+}
+
+/* Returns number of bytes "eaten" by the operand, or
+   return -1 if an invalid operand was found, or -2 if
+   an opcode tabe error was found.
+   ADDR is the pc for this arg to be relative to.  */
+
+static int
+print_insn_arg (const char *d,
+               unsigned char *buffer,
+               unsigned char *p0,
+               bfd_vma addr,
+               disassemble_info *info)
+{
+  int val = 0;
+  int place = d[1];
+  unsigned char *p = p0;
+  int regno;
+  const char *regname;
+  unsigned char *p1;
+  double flval;
+  int flt_p;
+  bfd_signed_vma disp;
+  unsigned int uval;
+
+  switch (*d)
+    {
+    case 'c':          /* Cache identifier.  */
+      {
+        static char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" };
+        val = fetch_arg (buffer, place, 2, info);
+        (*info->fprintf_func) (info->stream, cacheFieldName[val]);
+        break;
+      }
+
+    case 'a':          /* Address register indirect only. Cf. case '+'.  */
+      {
+        (*info->fprintf_func)
+         (info->stream,
+          "%s@",
+          reg_names[fetch_arg (buffer, place, 3, info) + 8]);
+        break;
+      }
+
+    case '_':          /* 32-bit absolute address for move16.  */
+      {
+        uval = NEXTULONG (p);
+       (*info->print_address_func) (uval, info);
+        break;
+      }
+
+    case 'C':
+      (*info->fprintf_func) (info->stream, "%%ccr");
+      break;
+
+    case 'S':
+      (*info->fprintf_func) (info->stream, "%%sr");
+      break;
+
+    case 'U':
+      (*info->fprintf_func) (info->stream, "%%usp");
+      break;
+
+    case 'E':
+      (*info->fprintf_func) (info->stream, "%%acc");
+      break;
+
+    case 'G':
+      (*info->fprintf_func) (info->stream, "%%macsr");
+      break;
+
+    case 'H':
+      (*info->fprintf_func) (info->stream, "%%mask");
+      break;
+
+    case 'J':
+      {
+       /* FIXME: There's a problem here, different m68k processors call the
+          same address different names. This table can't get it right
+          because it doesn't know which processor it's disassembling for.  */
+       static const struct { char *name; int value; } names[]
+         = {{"%sfc", 0x000}, {"%dfc", 0x001}, {"%cacr", 0x002},
+            {"%tc",  0x003}, {"%itt0",0x004}, {"%itt1", 0x005},
+             {"%dtt0",0x006}, {"%dtt1",0x007}, {"%buscr",0x008},
+            {"%usp", 0x800}, {"%vbr", 0x801}, {"%caar", 0x802},
+            {"%msp", 0x803}, {"%isp", 0x804},
+            {"%flashbar", 0xc04}, {"%rambar", 0xc05}, /* mcf528x added these.  */
+
+            /* Should we be calling this psr like we do in case 'Y'?  */
+            {"%mmusr",0x805},
+
+             {"%urp", 0x806}, {"%srp", 0x807}, {"%pcr", 0x808}};
+
+       val = fetch_arg (buffer, place, 12, info);
+       for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
+         if (names[regno].value == val)
+           {
+             (*info->fprintf_func) (info->stream, "%s", names[regno].name);
+             break;
+           }
+       if (regno < 0)
+         (*info->fprintf_func) (info->stream, "%d", val);
+      }
+      break;
+
+    case 'Q':
+      val = fetch_arg (buffer, place, 3, info);
+      /* 0 means 8, except for the bkpt instruction... */
+      if (val == 0 && d[1] != 's')
+       val = 8;
+      (*info->fprintf_func) (info->stream, "#%d", val);
+      break;
+
+    case 'x':
+      val = fetch_arg (buffer, place, 3, info);
+      /* 0 means -1.  */
+      if (val == 0)
+       val = -1;
+      (*info->fprintf_func) (info->stream, "#%d", val);
+      break;
+
+    case 'M':
+      if (place == 'h')
+       {
+         static char *const scalefactor_name[] = { "<<", ">>" };
+         val = fetch_arg (buffer, place, 1, info);
+         (*info->fprintf_func) (info->stream, scalefactor_name[val]);
+       }
+      else
+       {
+         val = fetch_arg (buffer, place, 8, info);
+         if (val & 0x80)
+           val = val - 0x100;
+         (*info->fprintf_func) (info->stream, "#%d", val);
+       }
+      break;
+
+    case 'T':
+      val = fetch_arg (buffer, place, 4, info);
+      (*info->fprintf_func) (info->stream, "#%d", val);
+      break;
+
+    case 'D':
+      (*info->fprintf_func) (info->stream, "%s",
+                            reg_names[fetch_arg (buffer, place, 3, info)]);
+      break;
+
+    case 'A':
+      (*info->fprintf_func)
+       (info->stream, "%s",
+        reg_names[fetch_arg (buffer, place, 3, info) + 010]);
+      break;
+
+    case 'R':
+      (*info->fprintf_func)
+       (info->stream, "%s",
+        reg_names[fetch_arg (buffer, place, 4, info)]);
+      break;
+
+    case 'r':
+      regno = fetch_arg (buffer, place, 4, info);
+      if (regno > 7)
+       (*info->fprintf_func) (info->stream, "%s@", reg_names[regno]);
+      else
+       (*info->fprintf_func) (info->stream, "@(%s)", reg_names[regno]);
+      break;
+
+    case 'F':
+      (*info->fprintf_func)
+       (info->stream, "%%fp%d",
+        fetch_arg (buffer, place, 3, info));
+      break;
+
+    case 'O':
+      val = fetch_arg (buffer, place, 6, info);
+      if (val & 0x20)
+       (*info->fprintf_func) (info->stream, "%s", reg_names[val & 7]);
+      else
+       (*info->fprintf_func) (info->stream, "%d", val);
+      break;
+
+    case '+':
+      (*info->fprintf_func)
+       (info->stream, "%s@+",
+        reg_names[fetch_arg (buffer, place, 3, info) + 8]);
+      break;
+
+    case '-':
+      (*info->fprintf_func)
+       (info->stream, "%s@-",
+        reg_names[fetch_arg (buffer, place, 3, info) + 8]);
+      break;
+
+    case 'k':
+      if (place == 'k')
+       (*info->fprintf_func)
+         (info->stream, "{%s}",
+          reg_names[fetch_arg (buffer, place, 3, info)]);
+      else if (place == 'C')
+       {
+         val = fetch_arg (buffer, place, 7, info);
+         if (val > 63)         /* This is a signed constant.  */
+           val -= 128;
+         (*info->fprintf_func) (info->stream, "{#%d}", val);
+       }
+      else
+       return -2;
+      break;
+
+    case '#':
+    case '^':
+      p1 = buffer + (*d == '#' ? 2 : 4);
+      if (place == 's')
+       val = fetch_arg (buffer, place, 4, info);
+      else if (place == 'C')
+       val = fetch_arg (buffer, place, 7, info);
+      else if (place == '8')
+       val = fetch_arg (buffer, place, 3, info);
+      else if (place == '3')
+       val = fetch_arg (buffer, place, 8, info);
+      else if (place == 'b')
+       val = NEXTBYTE (p1);
+      else if (place == 'w' || place == 'W')
+       val = NEXTWORD (p1);
+      else if (place == 'l')
+       val = NEXTLONG (p1);
+      else
+       return -2;
+      (*info->fprintf_func) (info->stream, "#%d", val);
+      break;
+
+    case 'B':
+      if (place == 'b')
+       disp = NEXTBYTE (p);
+      else if (place == 'B')
+       disp = COERCE_SIGNED_CHAR (buffer[1]);
+      else if (place == 'w' || place == 'W')
+       disp = NEXTWORD (p);
+      else if (place == 'l' || place == 'L' || place == 'C')
+       disp = NEXTLONG (p);
+      else if (place == 'g')
+       {
+         disp = NEXTBYTE (buffer);
+         if (disp == 0)
+           disp = NEXTWORD (p);
+         else if (disp == -1)
+           disp = NEXTLONG (p);
+       }
+      else if (place == 'c')
+       {
+         if (buffer[1] & 0x40)         /* If bit six is one, long offset.  */
+           disp = NEXTLONG (p);
+         else
+           disp = NEXTWORD (p);
+       }
+      else
+       return -2;
+
+      (*info->print_address_func) (addr + disp, info);
+      break;
+
+    case 'd':
+      val = NEXTWORD (p);
+      (*info->fprintf_func)
+       (info->stream, "%s@(%d)",
+        reg_names[fetch_arg (buffer, place, 3, info) + 8], val);
+      break;
+
+    case 's':
+      (*info->fprintf_func) (info->stream, "%s",
+                            fpcr_names[fetch_arg (buffer, place, 3, info)]);
+      break;
+
+    case 'e':
+      val = fetch_arg(buffer, place, 2, info);
+      (*info->fprintf_func) (info->stream, "%%acc%d", val);
+      break;
+
+    case 'g':
+      val = fetch_arg(buffer, place, 1, info);
+      (*info->fprintf_func) (info->stream, "%%accext%s", val==0 ? "01" : "23");
+      break;
+
+    case 'i':
+      val = fetch_arg(buffer, place, 2, info);
+      if (val == 1)
+       (*info->fprintf_func) (info->stream, "<<");
+      else if (val == 3)
+       (*info->fprintf_func) (info->stream, ">>");
+      else
+       return -1;
+      break;
+
+    case 'I':
+      /* Get coprocessor ID... */
+      val = fetch_arg (buffer, 'd', 3, info);
+
+      if (val != 1)                            /* Unusual coprocessor ID?  */
+       (*info->fprintf_func) (info->stream, "(cpid=%d) ", val);
+      break;
+
+    case '4':
+    case '*':
+    case '~':
+    case '%':
+    case ';':
+    case '@':
+    case '!':
+    case '$':
+    case '?':
+    case '/':
+    case '&':
+    case '|':
+    case '<':
+    case '>':
+    case 'm':
+    case 'n':
+    case 'o':
+    case 'p':
+    case 'q':
+    case 'v':
+    case 'b':
+    case 'w':
+    case 'y':
+    case 'z':
+      if (place == 'd')
+       {
+         val = fetch_arg (buffer, 'x', 6, info);
+         val = ((val & 7) << 3) + ((val >> 3) & 7);
+       }
+      else
+       val = fetch_arg (buffer, 's', 6, info);
+
+      /* If the <ea> is invalid for *d, then reject this match.  */
+      if (!m68k_valid_ea (*d, val))
+       return -1;
+
+      /* Get register number assuming address register.  */
+      regno = (val & 7) + 8;
+      regname = reg_names[regno];
+      switch (val >> 3)
+       {
+       case 0:
+         (*info->fprintf_func) (info->stream, "%s", reg_names[val]);
+         break;
+
+       case 1:
+         (*info->fprintf_func) (info->stream, "%s", regname);
+         break;
+
+       case 2:
+         (*info->fprintf_func) (info->stream, "%s@", regname);
+         break;
+
+       case 3:
+         (*info->fprintf_func) (info->stream, "%s@+", regname);
+         break;
+
+       case 4:
+         (*info->fprintf_func) (info->stream, "%s@-", regname);
+         break;
+
+       case 5:
+         val = NEXTWORD (p);
+         (*info->fprintf_func) (info->stream, "%s@(%d)", regname, val);
+         break;
+
+       case 6:
+         p = print_indexed (regno, p, addr, info);
+         break;
+
+       case 7:
+         switch (val & 7)
+           {
+           case 0:
+             val = NEXTWORD (p);
+             (*info->print_address_func) (val, info);
+             break;
+
+           case 1:
+             uval = NEXTULONG (p);
+             (*info->print_address_func) (uval, info);
+             break;
+
+           case 2:
+             val = NEXTWORD (p);
+             (*info->fprintf_func) (info->stream, "%%pc@(");
+             (*info->print_address_func) (addr + val, info);
+             (*info->fprintf_func) (info->stream, ")");
+             break;
+
+           case 3:
+             p = print_indexed (-1, p, addr, info);
+             break;
+
+           case 4:
+             flt_p = 1;        /* Assume it's a float... */
+             switch (place)
+             {
+               case 'b':
+                 val = NEXTBYTE (p);
+                 flt_p = 0;
+                 break;
+
+               case 'w':
+                 val = NEXTWORD (p);
+                 flt_p = 0;
+                 break;
+
+               case 'l':
+                 val = NEXTLONG (p);
+                 flt_p = 0;
+                 break;
+
+               case 'f':
+                 NEXTSINGLE (flval, p);
+                 break;
+
+               case 'F':
+                 NEXTDOUBLE (flval, p);
+                 break;
+
+               case 'x':
+                 NEXTEXTEND (flval, p);
+                 break;
+
+               case 'p':
+                 flval = NEXTPACKED (p);
+                 break;
+
+               default:
+                 return -1;
+             }
+             if (flt_p)        /* Print a float? */
+               (*info->fprintf_func) (info->stream, "#%g", flval);
+             else
+               (*info->fprintf_func) (info->stream, "#%d", val);
+             break;
+
+           default:
+             return -1;
+           }
+       }
+
+      /* If place is '/', then this is the case of the mask bit for
+        mac/emac loads. Now that the arg has been printed, grab the
+        mask bit and if set, add a '&' to the arg.  */
+      if (place == '/')
+       {
+         val = fetch_arg (buffer, place, 1, info);
+         if (val)
+           info->fprintf_func (info->stream, "&");
+       }
+      break;
+
+    case 'L':
+    case 'l':
+       if (place == 'w')
+         {
+           char doneany;
+           p1 = buffer + 2;
+           val = NEXTWORD (p1);
+           /* Move the pointer ahead if this point is farther ahead
+              than the last.  */
+           p = p1 > p ? p1 : p;
+           if (val == 0)
+             {
+               (*info->fprintf_func) (info->stream, "#0");
+               break;
+             }
+           if (*d == 'l')
+             {
+               int newval = 0;
+
+               for (regno = 0; regno < 16; ++regno)
+                 if (val & (0x8000 >> regno))
+                   newval |= 1 << regno;
+               val = newval;
+             }
+           val &= 0xffff;
+           doneany = 0;
+           for (regno = 0; regno < 16; ++regno)
+             if (val & (1 << regno))
+               {
+                 int first_regno;
+
+                 if (doneany)
+                   (*info->fprintf_func) (info->stream, "/");
+                 doneany = 1;
+                 (*info->fprintf_func) (info->stream, "%s", reg_names[regno]);
+                 first_regno = regno;
+                 while (val & (1 << (regno + 1)))
+                   ++regno;
+                 if (regno > first_regno)
+                   (*info->fprintf_func) (info->stream, "-%s",
+                                          reg_names[regno]);
+               }
+         }
+       else if (place == '3')
+         {
+           /* `fmovem' insn.  */
+           char doneany;
+           val = fetch_arg (buffer, place, 8, info);
+           if (val == 0)
+             {
+               (*info->fprintf_func) (info->stream, "#0");
+               break;
+             }
+           if (*d == 'l')
+             {
+               int newval = 0;
+
+               for (regno = 0; regno < 8; ++regno)
+                 if (val & (0x80 >> regno))
+                   newval |= 1 << regno;
+               val = newval;
+             }
+           val &= 0xff;
+           doneany = 0;
+           for (regno = 0; regno < 8; ++regno)
+             if (val & (1 << regno))
+               {
+                 int first_regno;
+                 if (doneany)
+                   (*info->fprintf_func) (info->stream, "/");
+                 doneany = 1;
+                 (*info->fprintf_func) (info->stream, "%%fp%d", regno);
+                 first_regno = regno;
+                 while (val & (1 << (regno + 1)))
+                   ++regno;
+                 if (regno > first_regno)
+                   (*info->fprintf_func) (info->stream, "-%%fp%d", regno);
+               }
+         }
+       else if (place == '8')
+         {
+           /* fmoveml for FP status registers.  */
+           (*info->fprintf_func) (info->stream, "%s",
+                                  fpcr_names[fetch_arg (buffer, place, 3,
+                                                        info)]);
+         }
+       else
+         return -2;
+      break;
+
+    case 'X':
+      place = '8';
+    case 'Y':
+    case 'Z':
+    case 'W':
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+      {
+       int val = fetch_arg (buffer, place, 5, info);
+       char *name = 0;
+
+       switch (val)
+         {
+         case 2: name = "%tt0"; break;
+         case 3: name = "%tt1"; break;
+         case 0x10: name = "%tc"; break;
+         case 0x11: name = "%drp"; break;
+         case 0x12: name = "%srp"; break;
+         case 0x13: name = "%crp"; break;
+         case 0x14: name = "%cal"; break;
+         case 0x15: name = "%val"; break;
+         case 0x16: name = "%scc"; break;
+         case 0x17: name = "%ac"; break;
+         case 0x18: name = "%psr"; break;
+         case 0x19: name = "%pcsr"; break;
+         case 0x1c:
+         case 0x1d:
+           {
+             int break_reg = ((buffer[3] >> 2) & 7);
+
+             (*info->fprintf_func)
+               (info->stream, val == 0x1c ? "%%bad%d" : "%%bac%d",
+                break_reg);
+           }
+           break;
+         default:
+           (*info->fprintf_func) (info->stream, "<mmu register %d>", val);
+         }
+       if (name)
+         (*info->fprintf_func) (info->stream, "%s", name);
+      }
+      break;
+
+    case 'f':
+      {
+       int fc = fetch_arg (buffer, place, 5, info);
+
+       if (fc == 1)
+         (*info->fprintf_func) (info->stream, "%%dfc");
+       else if (fc == 0)
+         (*info->fprintf_func) (info->stream, "%%sfc");
+       else
+         /* xgettext:c-format */
+         (*info->fprintf_func) (info->stream, _("<function code %d>"), fc);
+      }
+      break;
+
+    case 'V':
+      (*info->fprintf_func) (info->stream, "%%val");
+      break;
+
+    case 't':
+      {
+       int level = fetch_arg (buffer, place, 3, info);
+
+       (*info->fprintf_func) (info->stream, "%d", level);
+      }
+      break;
+
+    case 'u':
+      {
+       short is_upper = 0;
+       int reg = fetch_arg (buffer, place, 5, info);
+
+       if (reg & 0x10)
+         {
+           is_upper = 1;
+           reg &= 0xf;
+         }
+       (*info->fprintf_func) (info->stream, "%s%s",
+                              reg_half_names[reg],
+                              is_upper ? "u" : "l");
+      }
+      break;
+
+    default:
+      return -2;
+    }
+
+  return p - p0;
+}
+
+/* Try to match the current instruction to best and if so, return the
+   number of bytes consumed from the instruction stream, else zero.  */
+
+static int
+match_insn_m68k (bfd_vma memaddr,
+                disassemble_info * info,
+                const struct m68k_opcode * best,
+                struct private * priv)
+{
+  unsigned char *save_p;
+  unsigned char *p;
+  const char *d;
+
+  bfd_byte *buffer = priv->the_buffer;
+  fprintf_ftype save_printer = info->fprintf_func;
+  void (* save_print_address) (bfd_vma, struct disassemble_info *)
+    = info->print_address_func;
+
+  /* Point at first word of argument data,
+     and at descriptor for first argument.  */
+  p = buffer + 2;
+
+  /* Figure out how long the fixed-size portion of the instruction is.
+     The only place this is stored in the opcode table is
+     in the arguments--look for arguments which specify fields in the 2nd
+     or 3rd words of the instruction.  */
+  for (d = best->args; *d; d += 2)
+    {
+      /* I don't think it is necessary to be checking d[0] here;
+        I suspect all this could be moved to the case statement below.  */
+      if (d[0] == '#')
+       {
+         if (d[1] == 'l' && p - buffer < 6)
+           p = buffer + 6;
+         else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8')
+           p = buffer + 4;
+       }
+
+      if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
+       p = buffer + 4;
+
+      switch (d[1])
+       {
+       case '1':
+       case '2':
+       case '3':
+       case '7':
+       case '8':
+       case '9':
+       case 'i':
+         if (p - buffer < 4)
+           p = buffer + 4;
+         break;
+       case '4':
+       case '5':
+       case '6':
+         if (p - buffer < 6)
+           p = buffer + 6;
+         break;
+       default:
+         break;
+       }
+    }
+
+  /* pflusha is an exceptions.  It takes no arguments but is two words
+     long.  Recognize it by looking at the lower 16 bits of the mask.  */
+  if (p - buffer < 4 && (best->match & 0xFFFF) != 0)
+    p = buffer + 4;
+
+  /* lpstop is another exception.  It takes a one word argument but is
+     three words long.  */
+  if (p - buffer < 6
+      && (best->match & 0xffff) == 0xffff
+      && best->args[0] == '#'
+      && best->args[1] == 'w')
+    {
+      /* Copy the one word argument into the usual location for a one
+        word argument, to simplify printing it.  We can get away with
+        this because we know exactly what the second word is, and we
+        aren't going to print anything based on it.  */
+      p = buffer + 6;
+      FETCH_DATA (info, p);
+      buffer[2] = buffer[4];
+      buffer[3] = buffer[5];
+    }
+
+  FETCH_DATA (info, p);
+
+  d = best->args;
+
+  save_p = p;
+  info->print_address_func = dummy_print_address;
+  info->fprintf_func = (fprintf_ftype) dummy_printer;
+
+  /* We scan the operands twice.  The first time we don't print anything,
+     but look for errors.  */
+  for (; *d; d += 2)
+    {
+      int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
+
+      if (eaten >= 0)
+       p += eaten;
+      else if (eaten == -1)
+       {
+         info->fprintf_func = save_printer;
+         info->print_address_func = save_print_address;
+         return 0;
+       }
+      else
+       {
+         info->fprintf_func (info->stream,
+                             /* xgettext:c-format */
+                             _("<internal error in opcode table: %s %s>\n"),
+                             best->name,  best->args);
+         info->fprintf_func = save_printer;
+         info->print_address_func = save_print_address;
+         return 2;
+       }
+    }
+
+  p = save_p;
+  info->fprintf_func = save_printer;
+  info->print_address_func = save_print_address;
+
+  d = best->args;
+
+  info->fprintf_func (info->stream, "%s", best->name);
+
+  if (*d)
+    info->fprintf_func (info->stream, " ");
+
+  while (*d)
+    {
+      p += print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
+      d += 2;
+
+      if (*d && *(d - 2) != 'I' && *d != 'k')
+       info->fprintf_func (info->stream, ",");
+    }
+
+  return p - buffer;
+}
+
+/* Print the m68k instruction at address MEMADDR in debugged memory,
+   on INFO->STREAM.  Returns length of the instruction, in bytes.  */
+
+int
+print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
+{
+  int i;
+  const char *d;
+  unsigned int arch_mask;
+  struct private priv;
+  bfd_byte *buffer = priv.the_buffer;
+  int major_opcode;
+  static int numopcodes[16];
+  static const struct m68k_opcode **opcodes[16];
+  int val;
+
+  if (!opcodes[0])
+    {
+      /* Speed up the matching by sorting the opcode
+        table on the upper four bits of the opcode.  */
+      const struct m68k_opcode **opc_pointer[16];
+
+      /* First count how many opcodes are in each of the sixteen buckets.  */
+      for (i = 0; i < m68k_numopcodes; i++)
+       numopcodes[(m68k_opcodes[i].opcode >> 28) & 15]++;
+
+      /* Then create a sorted table of pointers
+        that point into the unsorted table.  */
+      opc_pointer[0] = malloc (sizeof (struct m68k_opcode *)
+                               * m68k_numopcodes);
+      opcodes[0] = opc_pointer[0];
+
+      for (i = 1; i < 16; i++)
+       {
+         opc_pointer[i] = opc_pointer[i - 1] + numopcodes[i - 1];
+         opcodes[i] = opc_pointer[i];
+       }
+
+      for (i = 0; i < m68k_numopcodes; i++)
+       *opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i];
+    }
+
+  info->private_data = (PTR) &priv;
+  /* Tell objdump to use two bytes per chunk
+     and six bytes per line for displaying raw data.  */
+  info->bytes_per_chunk = 2;
+  info->bytes_per_line = 6;
+  info->display_endian = BFD_ENDIAN_BIG;
+  priv.max_fetched = priv.the_buffer;
+  priv.insn_start = memaddr;
+
+  if (setjmp (priv.bailout) != 0)
+    /* Error return.  */
+    return -1;
+
+  switch (info->mach)
+    {
+    default:
+    case 0:
+      arch_mask = (unsigned int) -1;
+      break;
+    case bfd_mach_m68000:
+      arch_mask = m68000|m68881|m68851;
+      break;
+    case bfd_mach_m68008:
+      arch_mask = m68008|m68881|m68851;
+      break;
+    case bfd_mach_m68010:
+      arch_mask = m68010|m68881|m68851;
+      break;
+    case bfd_mach_m68020:
+      arch_mask = m68020|m68881|m68851;
+      break;
+    case bfd_mach_m68030:
+      arch_mask = m68030|m68881|m68851;
+      break;
+    case bfd_mach_m68040:
+      arch_mask = m68040|m68881|m68851;
+      break;
+    case bfd_mach_m68060:
+      arch_mask = m68060|m68881|m68851;
+      break;
+    case bfd_mach_mcf5200:
+      arch_mask = mcfisa_a;
+      break;
+    case bfd_mach_mcf521x:
+    case bfd_mach_mcf528x:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfisa_aa|mcfusp|mcfemac;
+      break;
+    case bfd_mach_mcf5206e:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfmac;
+      break;
+    case bfd_mach_mcf5249:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfemac;
+      break;
+    case bfd_mach_mcf5307:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfmac;
+      break;
+    case bfd_mach_mcf5407:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfmac;
+      break;
+    case bfd_mach_mcf547x:
+    case bfd_mach_mcf548x:
+    case bfd_mach_mcfv4e:
+      arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp|cfloat|mcfemac;
+      break;
+    }
+
+  FETCH_DATA (info, buffer + 2);
+  major_opcode = (buffer[0] >> 4) & 15;
+
+  for (i = 0; i < numopcodes[major_opcode]; i++)
+    {
+      const struct m68k_opcode *opc = opcodes[major_opcode][i];
+      unsigned long opcode = opc->opcode;
+      unsigned long match = opc->match;
+
+      if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
+         && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
+         /* Only fetch the next two bytes if we need to.  */
+         && (((0xffff & match) == 0)
+             ||
+             (FETCH_DATA (info, buffer + 4)
+              && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
+              && ((0xff & buffer[3] & match) == (0xff & opcode)))
+             )
+         && (opc->arch & arch_mask) != 0)
+       {
+         /* Don't use for printout the variants of divul and divsl
+            that have the same register number in two places.
+            The more general variants will match instead.  */
+         for (d = opc->args; *d; d += 2)
+           if (d[1] == 'D')
+             break;
+
+         /* Don't use for printout the variants of most floating
+            point coprocessor instructions which use the same
+            register number in two places, as above.  */
+         if (*d == '\0')
+           for (d = opc->args; *d; d += 2)
+             if (d[1] == 't')
+               break;
+
+         /* Don't match fmovel with more than one register;
+            wait for fmoveml.  */
+         if (*d == '\0')
+           {
+             for (d = opc->args; *d; d += 2)
+               {
+                 if (d[0] == 's' && d[1] == '8')
+                   {
+                     val = fetch_arg (buffer, d[1], 3, info);
+                     if ((val & (val - 1)) != 0)
+                       break;
+                   }
+               }
+           }
+
+         if (*d == '\0')
+           if ((val = match_insn_m68k (memaddr, info, opc, & priv)))
+             return val;
+       }
+    }
+
+  /* Handle undefined instructions.  */
+  info->fprintf_func (info->stream, "0%o", (buffer[0] << 8) + buffer[1]);
+  return 2;
+}
+/* **** End of m68k-dis.c */
+/* **** m68k-opc.h from sourceware.org CVS 2005-08-14.  */
+/* Opcode table for m680[012346]0/m6888[12]/m68851/mcf5200.
+   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2003, 2004, 2005
+   Free Software Foundation, Inc.
+
+   This file is part of GDB, GAS, and the GNU binutils.
+
+   GDB, GAS, and the GNU binutils are free software; you can redistribute
+   them and/or modify them under the terms of the GNU General Public
+   License as published by the Free Software Foundation; either version
+   1, or (at your option) any later version.
+
+   GDB, GAS, and the GNU binutils are distributed in the hope that they
+   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.  */
+
+#define one(x) ((unsigned int) (x) << 16)
+#define two(x, y) (((unsigned int) (x) << 16) + (y))
+
+/* The assembler requires that all instances of the same mnemonic must
+   be consecutive.  If they aren't, the assembler will bomb at
+   runtime.  */
+
+const struct m68k_opcode m68k_opcodes[] =
+{
+{"abcd", 2,    one(0140400),   one(0170770), "DsDd", m68000up },
+{"abcd", 2,    one(0140410),   one(0170770), "-s-d", m68000up },
+
+{"addaw", 2,   one(0150300),   one(0170700), "*wAd", m68000up },
+{"addal", 2,   one(0150700),   one(0170700), "*lAd", m68000up | mcfisa_a },
+
+{"addib", 4,   one(0003000),   one(0177700), "#b$s", m68000up },
+{"addiw", 4,   one(0003100),   one(0177700), "#w$s", m68000up },
+{"addil", 6,   one(0003200),   one(0177700), "#l$s", m68000up },
+{"addil", 6,   one(0003200),   one(0177700), "#lDs", mcfisa_a },
+
+{"addqb", 2,   one(0050000),   one(0170700), "Qd$b", m68000up },
+{"addqw", 2,   one(0050100),   one(0170700), "Qd%w", m68000up },
+{"addql", 2,   one(0050200),   one(0170700), "Qd%l", m68000up | mcfisa_a },
+
+/* The add opcode can generate the adda, addi, and addq instructions.  */
+{"addb", 2,    one(0050000),   one(0170700), "Qd$b", m68000up },
+{"addb", 4,    one(0003000),   one(0177700), "#b$s", m68000up },
+{"addb", 2,    one(0150000),   one(0170700), ";bDd", m68000up },
+{"addb", 2,    one(0150400),   one(0170700), "Dd~b", m68000up },
+{"addw", 2,    one(0050100),   one(0170700), "Qd%w", m68000up },
+{"addw", 2,    one(0150300),   one(0170700), "*wAd", m68000up },
+{"addw", 4,    one(0003100),   one(0177700), "#w$s", m68000up },
+{"addw", 2,    one(0150100),   one(0170700), "*wDd", m68000up },
+{"addw", 2,    one(0150500),   one(0170700), "Dd~w", m68000up },
+{"addl", 2,    one(0050200),   one(0170700), "Qd%l", m68000up | mcfisa_a },
+{"addl", 6,    one(0003200),   one(0177700), "#l$s", m68000up },
+{"addl", 6,    one(0003200),   one(0177700), "#lDs", mcfisa_a },
+{"addl", 2,    one(0150700),   one(0170700), "*lAd", m68000up | mcfisa_a },
+{"addl", 2,    one(0150200),   one(0170700), "*lDd", m68000up | mcfisa_a },
+{"addl", 2,    one(0150600),   one(0170700), "Dd~l", m68000up | mcfisa_a },
+
+{"addxb", 2,   one(0150400),   one(0170770), "DsDd", m68000up },
+{"addxb", 2,   one(0150410),   one(0170770), "-s-d", m68000up },
+{"addxw", 2,   one(0150500),   one(0170770), "DsDd", m68000up },
+{"addxw", 2,   one(0150510),   one(0170770), "-s-d", m68000up },
+{"addxl", 2,   one(0150600),   one(0170770), "DsDd", m68000up | mcfisa_a },
+{"addxl", 2,   one(0150610),   one(0170770), "-s-d", m68000up },
+
+{"andib", 4,   one(0001000),   one(0177700), "#b$s", m68000up },
+{"andib", 4,   one(0001074),   one(0177777), "#bCs", m68000up },
+{"andiw", 4,   one(0001100),   one(0177700), "#w$s", m68000up },
+{"andiw", 4,   one(0001174),   one(0177777), "#wSs", m68000up },
+{"andil", 6,   one(0001200),   one(0177700), "#l$s", m68000up },
+{"andil", 6,   one(0001200),   one(0177700), "#lDs", mcfisa_a },
+{"andi", 4,    one(0001100),   one(0177700), "#w$s", m68000up },
+{"andi", 4,    one(0001074),   one(0177777), "#bCs", m68000up },
+{"andi", 4,    one(0001174),   one(0177777), "#wSs", m68000up },
+
+/* The and opcode can generate the andi instruction.  */
+{"andb", 4,    one(0001000),   one(0177700), "#b$s", m68000up },
+{"andb", 4,    one(0001074),   one(0177777), "#bCs", m68000up },
+{"andb", 2,    one(0140000),   one(0170700), ";bDd", m68000up },
+{"andb", 2,    one(0140400),   one(0170700), "Dd~b", m68000up },
+{"andw", 4,    one(0001100),   one(0177700), "#w$s", m68000up },
+{"andw", 4,    one(0001174),   one(0177777), "#wSs", m68000up },
+{"andw", 2,    one(0140100),   one(0170700), ";wDd", m68000up },
+{"andw", 2,    one(0140500),   one(0170700), "Dd~w", m68000up },
+{"andl", 6,    one(0001200),   one(0177700), "#l$s", m68000up },
+{"andl", 6,    one(0001200),   one(0177700), "#lDs", mcfisa_a },
+{"andl", 2,    one(0140200),   one(0170700), ";lDd", m68000up | mcfisa_a },
+{"andl", 2,    one(0140600),   one(0170700), "Dd~l", m68000up | mcfisa_a },
+{"and", 4,     one(0001100),   one(0177700), "#w$w", m68000up },
+{"and", 4,     one(0001074),   one(0177777), "#bCs", m68000up },
+{"and", 4,     one(0001174),   one(0177777), "#wSs", m68000up },
+{"and", 2,     one(0140100),   one(0170700), ";wDd", m68000up },
+{"and", 2,     one(0140500),   one(0170700), "Dd~w", m68000up },
+
+{"aslb", 2,    one(0160400),   one(0170770), "QdDs", m68000up },
+{"aslb", 2,    one(0160440),   one(0170770), "DdDs", m68000up },
+{"aslw", 2,    one(0160500),   one(0170770), "QdDs", m68000up },
+{"aslw", 2,    one(0160540),   one(0170770), "DdDs", m68000up },
+{"aslw", 2,    one(0160700),   one(0177700), "~s",   m68000up },
+{"asll", 2,    one(0160600),   one(0170770), "QdDs", m68000up | mcfisa_a },
+{"asll", 2,    one(0160640),   one(0170770), "DdDs", m68000up | mcfisa_a },
+
+{"asrb", 2,    one(0160000),   one(0170770), "QdDs", m68000up },
+{"asrb", 2,    one(0160040),   one(0170770), "DdDs", m68000up },
+{"asrw", 2,    one(0160100),   one(0170770), "QdDs", m68000up },
+{"asrw", 2,    one(0160140),   one(0170770), "DdDs", m68000up },
+{"asrw", 2,    one(0160300),   one(0177700), "~s",   m68000up },
+{"asrl", 2,    one(0160200),   one(0170770), "QdDs", m68000up | mcfisa_a },
+{"asrl", 2,    one(0160240),   one(0170770), "DdDs", m68000up | mcfisa_a },
+
+{"bhiw", 2,    one(0061000),   one(0177777), "BW", m68000up | mcfisa_a },
+{"blsw", 2,    one(0061400),   one(0177777), "BW", m68000up | mcfisa_a },
+{"bccw", 2,    one(0062000),   one(0177777), "BW", m68000up | mcfisa_a },
+{"bcsw", 2,    one(0062400),   one(0177777), "BW", m68000up | mcfisa_a },
+{"bnew", 2,    one(0063000),   one(0177777), "BW", m68000up | mcfisa_a },
+{"beqw", 2,    one(0063400),   one(0177777), "BW", m68000up | mcfisa_a },
+{"bvcw", 2,    one(0064000),   one(0177777), "BW", m68000up | mcfisa_a },
+{"bvsw", 2,    one(0064400),   one(0177777), "BW", m68000up | mcfisa_a },
+{"bplw", 2,    one(0065000),   one(0177777), "BW", m68000up | mcfisa_a },
+{"bmiw", 2,    one(0065400),   one(0177777), "BW", m68000up | mcfisa_a },
+{"bgew", 2,    one(0066000),   one(0177777), "BW", m68000up | mcfisa_a },
+{"bltw", 2,    one(0066400),   one(0177777), "BW", m68000up | mcfisa_a },
+{"bgtw", 2,    one(0067000),   one(0177777), "BW", m68000up | mcfisa_a },
+{"blew", 2,    one(0067400),   one(0177777), "BW", m68000up | mcfisa_a },
+
+{"bhil", 2,    one(0061377),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"blsl", 2,    one(0061777),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bccl", 2,    one(0062377),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bcsl", 2,    one(0062777),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bnel", 2,    one(0063377),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"beql", 2,    one(0063777),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bvcl", 2,    one(0064377),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bvsl", 2,    one(0064777),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bpll", 2,    one(0065377),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bmil", 2,    one(0065777),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bgel", 2,    one(0066377),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bltl", 2,    one(0066777),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bgtl", 2,    one(0067377),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"blel", 2,    one(0067777),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+
+{"bhis", 2,    one(0061000),   one(0177400), "BB", m68000up | mcfisa_a },
+{"blss", 2,    one(0061400),   one(0177400), "BB", m68000up | mcfisa_a },
+{"bccs", 2,    one(0062000),   one(0177400), "BB", m68000up | mcfisa_a },
+{"bcss", 2,    one(0062400),   one(0177400), "BB", m68000up | mcfisa_a },
+{"bnes", 2,    one(0063000),   one(0177400), "BB", m68000up | mcfisa_a },
+{"beqs", 2,    one(0063400),   one(0177400), "BB", m68000up | mcfisa_a },
+{"bvcs", 2,    one(0064000),   one(0177400), "BB", m68000up | mcfisa_a },
+{"bvss", 2,    one(0064400),   one(0177400), "BB", m68000up | mcfisa_a },
+{"bpls", 2,    one(0065000),   one(0177400), "BB", m68000up | mcfisa_a },
+{"bmis", 2,    one(0065400),   one(0177400), "BB", m68000up | mcfisa_a },
+{"bges", 2,    one(0066000),   one(0177400), "BB", m68000up | mcfisa_a },
+{"blts", 2,    one(0066400),   one(0177400), "BB", m68000up | mcfisa_a },
+{"bgts", 2,    one(0067000),   one(0177400), "BB", m68000up | mcfisa_a },
+{"bles", 2,    one(0067400),   one(0177400), "BB", m68000up | mcfisa_a },
+
+{"jhi", 2,     one(0061000),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jls", 2,     one(0061400),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jcc", 2,     one(0062000),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jcs", 2,     one(0062400),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jne", 2,     one(0063000),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jeq", 2,     one(0063400),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jvc", 2,     one(0064000),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jvs", 2,     one(0064400),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jpl", 2,     one(0065000),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jmi", 2,     one(0065400),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jge", 2,     one(0066000),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jlt", 2,     one(0066400),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jgt", 2,     one(0067000),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jle", 2,     one(0067400),   one(0177400), "Bg", m68000up | mcfisa_a },
+
+{"bchg", 2,    one(0000500),   one(0170700), "Dd$s", m68000up | mcfisa_a },
+{"bchg", 4,    one(0004100),   one(0177700), "#b$s", m68000up },
+{"bchg", 4,    one(0004100),   one(0177700), "#bqs", mcfisa_a },
+
+{"bclr", 2,    one(0000600),   one(0170700), "Dd$s", m68000up | mcfisa_a },
+{"bclr", 4,    one(0004200),   one(0177700), "#b$s", m68000up },
+{"bclr", 4,    one(0004200),   one(0177700), "#bqs", mcfisa_a },
+
+{"bfchg", 4,   two(0165300, 0), two(0177700, 0170000), "?sO2O3",   m68020up },
+{"bfclr", 4,   two(0166300, 0), two(0177700, 0170000), "?sO2O3",   m68020up },
+{"bfexts", 4,  two(0165700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up },
+{"bfextu", 4,  two(0164700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up },
+{"bfffo", 4,   two(0166700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up },
+{"bfins", 4,   two(0167700, 0), two(0177700, 0100000), "D1?sO2O3", m68020up },
+{"bfset", 4,   two(0167300, 0), two(0177700, 0170000), "?sO2O3",   m68020up },
+{"bftst", 4,   two(0164300, 0), two(0177700, 0170000), "/sO2O3",   m68020up },
+
+{"bgnd", 2,    one(0045372),   one(0177777), "", cpu32 },
+
+{"bitrev", 2,  one(0000300),   one(0177770), "Ds", mcfisa_aa},
+
+{"bkpt", 2,    one(0044110),   one(0177770), "ts", m68010up },
+
+{"braw", 2,    one(0060000),   one(0177777), "BW", m68000up | mcfisa_a },
+{"bral", 2,    one(0060377),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bras", 2,    one(0060000),   one(0177400), "BB", m68000up | mcfisa_a },
+
+{"bset", 2,    one(0000700),   one(0170700), "Dd$s", m68000up | mcfisa_a },
+{"bset", 2,    one(0000700),   one(0170700), "Ddvs", mcfisa_a },
+{"bset", 4,    one(0004300),   one(0177700), "#b$s", m68000up },
+{"bset", 4,    one(0004300),   one(0177700), "#bqs", mcfisa_a },
+
+{"bsrw", 2,    one(0060400),   one(0177777), "BW", m68000up | mcfisa_a },
+{"bsrl", 2,    one(0060777),   one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
+{"bsrs", 2,    one(0060400),   one(0177400), "BB", m68000up | mcfisa_a },
+
+{"btst", 2,    one(0000400),   one(0170700), "Dd;b", m68000up | mcfisa_a },
+{"btst", 4,    one(0004000),   one(0177700), "#b@s", m68000up },
+{"btst", 4,    one(0004000),   one(0177700), "#bqs", mcfisa_a },
+
+{"byterev", 2, one(0001300),   one(0177770), "Ds", mcfisa_aa},
+
+{"callm", 4,   one(0003300),   one(0177700), "#b!s", m68020 },
+
+{"cas2w", 6,    two(0006374,0), two(0177777,0007070), "D3D6D2D5r1r4", m68020up },
+{"cas2w", 6,    two(0006374,0), two(0177777,0007070), "D3D6D2D5R1R4", m68020up },
+{"cas2l", 6,    two(0007374,0), two(0177777,0007070), "D3D6D2D5r1r4", m68020up },
+{"cas2l", 6,    two(0007374,0), two(0177777,0007070), "D3D6D2D5R1R4", m68020up },
+
+{"casb", 4,    two(0005300, 0), two(0177700, 0177070), "D3D2~s", m68020up },
+{"casw", 4,    two(0006300, 0), two(0177700, 0177070), "D3D2~s", m68020up },
+{"casl", 4,    two(0007300, 0), two(0177700, 0177070), "D3D2~s", m68020up },
+
+{"chk2b", 4,   two(0000300,0004000), two(0177700,07777), "!sR1", m68020up | cpu32 },
+{"chk2w", 4,   two(0001300,0004000),   two(0177700,07777), "!sR1", m68020up | cpu32 },
+{"chk2l", 4,   two(0002300,0004000),   two(0177700,07777), "!sR1", m68020up | cpu32 },
+
+{"chkl", 2,    one(0040400),           one(0170700), ";lDd", m68000up },
+{"chkw", 2,    one(0040600),           one(0170700), ";wDd", m68000up },
+
+#define SCOPE_LINE (0x1 << 3)
+#define SCOPE_PAGE (0x2 << 3)
+#define SCOPE_ALL  (0x3 << 3)
+
+{"cinva", 2,   one(0xf400|SCOPE_ALL),  one(0xff38), "ce",   m68040up },
+{"cinvl", 2,   one(0xf400|SCOPE_LINE), one(0xff38), "ceas", m68040up },
+{"cinvp", 2,   one(0xf400|SCOPE_PAGE), one(0xff38), "ceas", m68040up },
+
+{"cpusha", 2,  one(0xf420|SCOPE_ALL),  one(0xff38), "ce",   m68040up },
+{"cpushl", 2,  one(0xf420|SCOPE_LINE), one(0xff38), "ceas", m68040up | mcfisa_a },
+{"cpushp", 2,  one(0xf420|SCOPE_PAGE), one(0xff38), "ceas", m68040up },
+
+#undef SCOPE_LINE
+#undef SCOPE_PAGE
+#undef SCOPE_ALL
+
+{"clrb", 2,    one(0041000),   one(0177700), "$s", m68000up | mcfisa_a },
+{"clrw", 2,    one(0041100),   one(0177700), "$s", m68000up | mcfisa_a },
+{"clrl", 2,    one(0041200),   one(0177700), "$s", m68000up | mcfisa_a },
+
+{"cmp2b", 4,   two(0000300,0), two(0177700,07777), "!sR1", m68020up | cpu32 },
+{"cmp2w", 4,   two(0001300,0), two(0177700,07777), "!sR1", m68020up | cpu32 },
+{"cmp2l", 4,   two(0002300,0), two(0177700,07777), "!sR1", m68020up | cpu32 },
+
+{"cmpaw", 2,   one(0130300),   one(0170700), "*wAd", m68000up },
+{"cmpal", 2,   one(0130700),   one(0170700), "*lAd", m68000up | mcfisa_a },
+
+{"cmpib", 4,   one(0006000),   one(0177700), "#b@s", m68000up },
+{"cmpib", 4,   one(0006000),   one(0177700), "#bDs", mcfisa_b },
+{"cmpiw", 4,   one(0006100),   one(0177700), "#w@s", m68000up },
+{"cmpiw", 4,   one(0006100),   one(0177700), "#wDs", mcfisa_b },
+{"cmpil", 6,   one(0006200),   one(0177700), "#l@s", m68000up },
+{"cmpil", 6,   one(0006200),   one(0177700), "#lDs", mcfisa_a },
+
+{"cmpmb", 2,   one(0130410),   one(0170770), "+s+d", m68000up },
+{"cmpmw", 2,   one(0130510),   one(0170770), "+s+d", m68000up },
+{"cmpml", 2,   one(0130610),   one(0170770), "+s+d", m68000up },
+
+/* The cmp opcode can generate the cmpa, cmpm, and cmpi instructions.  */
+{"cmpb", 4,    one(0006000),   one(0177700), "#b@s", m68000up },
+{"cmpb", 4,    one(0006000),   one(0177700), "#bDs", mcfisa_b },
+{"cmpb", 2,    one(0130410),   one(0170770), "+s+d", m68000up },
+{"cmpb", 2,    one(0130000),   one(0170700), ";bDd", m68000up },
+{"cmpb", 2,    one(0130000),   one(0170700), "*bDd", mcfisa_b },
+{"cmpw", 2,    one(0130300),   one(0170700), "*wAd", m68000up },
+{"cmpw", 4,    one(0006100),   one(0177700), "#w@s", m68000up },
+{"cmpw", 4,    one(0006100),   one(0177700), "#wDs", mcfisa_b },
+{"cmpw", 2,    one(0130510),   one(0170770), "+s+d", m68000up },
+{"cmpw", 2,    one(0130100),   one(0170700), "*wDd", m68000up | mcfisa_b },
+{"cmpl", 2,    one(0130700),   one(0170700), "*lAd", m68000up | mcfisa_a },
+{"cmpl", 6,    one(0006200),   one(0177700), "#l@s", m68000up },
+{"cmpl", 6,    one(0006200),   one(0177700), "#lDs", mcfisa_a },
+{"cmpl", 2,    one(0130610),   one(0170770), "+s+d", m68000up },
+{"cmpl", 2,    one(0130200),   one(0170700), "*lDd", m68000up | mcfisa_a },
+
+{"dbcc", 2,    one(0052310),   one(0177770), "DsBw", m68000up },
+{"dbcs", 2,    one(0052710),   one(0177770), "DsBw", m68000up },
+{"dbeq", 2,    one(0053710),   one(0177770), "DsBw", m68000up },
+{"dbf", 2,     one(0050710),   one(0177770), "DsBw", m68000up },
+{"dbge", 2,    one(0056310),   one(0177770), "DsBw", m68000up },
+{"dbgt", 2,    one(0057310),   one(0177770), "DsBw", m68000up },
+{"dbhi", 2,    one(0051310),   one(0177770), "DsBw", m68000up },
+{"dble", 2,    one(0057710),   one(0177770), "DsBw", m68000up },
+{"dbls", 2,    one(0051710),   one(0177770), "DsBw", m68000up },
+{"dblt", 2,    one(0056710),   one(0177770), "DsBw", m68000up },
+{"dbmi", 2,    one(0055710),   one(0177770), "DsBw", m68000up },
+{"dbne", 2,    one(0053310),   one(0177770), "DsBw", m68000up },
+{"dbpl", 2,    one(0055310),   one(0177770), "DsBw", m68000up },
+{"dbt", 2,     one(0050310),   one(0177770), "DsBw", m68000up },
+{"dbvc", 2,    one(0054310),   one(0177770), "DsBw", m68000up },
+{"dbvs", 2,    one(0054710),   one(0177770), "DsBw", m68000up },
+
+{"divsw", 2,   one(0100700),   one(0170700), ";wDd", m68000up | mcfhwdiv },
+
+{"divsl", 4,   two(0046100,0006000),two(0177700,0107770),";lD3D1", m68020up|cpu32 },
+{"divsl", 4,   two(0046100,0004000),two(0177700,0107770),";lDD",   m68020up|cpu32 },
+{"divsl", 4,   two(0046100,0004000),two(0177700,0107770),"qsDD",   mcfhwdiv },
+
+{"divsll", 4,  two(0046100,0004000),two(0177700,0107770),";lD3D1",m68020up|cpu32 },
+{"divsll", 4,  two(0046100,0004000),two(0177700,0107770),";lDD",  m68020up|cpu32 },
+
+{"divuw", 2,   one(0100300),           one(0170700), ";wDd", m68000up | mcfhwdiv },
+
+{"divul", 4,   two(0046100,0002000),two(0177700,0107770),";lD3D1", m68020up|cpu32 },
+{"divul", 4,   two(0046100,0000000),two(0177700,0107770),";lDD",   m68020up|cpu32 },
+{"divul", 4,   two(0046100,0000000),two(0177700,0107770),"qsDD",   mcfhwdiv },
+
+{"divull", 4,  two(0046100,0000000),two(0177700,0107770),";lD3D1",m68020up|cpu32 },
+{"divull", 4,  two(0046100,0000000),two(0177700,0107770),";lDD",  m68020up|cpu32 },
+
+{"eorib", 4,   one(0005000),   one(0177700), "#b$s", m68000up },
+{"eorib", 4,   one(0005074),   one(0177777), "#bCs", m68000up },
+{"eoriw", 4,   one(0005100),   one(0177700), "#w$s", m68000up },
+{"eoriw", 4,   one(0005174),   one(0177777), "#wSs", m68000up },
+{"eoril", 6,   one(0005200),   one(0177700), "#l$s", m68000up },
+{"eoril", 6,   one(0005200),   one(0177700), "#lDs", mcfisa_a },
+{"eori", 4,    one(0005074),   one(0177777), "#bCs", m68000up },
+{"eori", 4,    one(0005174),   one(0177777), "#wSs", m68000up },
+{"eori", 4,    one(0005100),   one(0177700), "#w$s", m68000up },
+
+/* The eor opcode can generate the eori instruction.  */
+{"eorb", 4,    one(0005000),   one(0177700), "#b$s", m68000up },
+{"eorb", 4,    one(0005074),   one(0177777), "#bCs", m68000up },
+{"eorb", 2,    one(0130400),   one(0170700), "Dd$s", m68000up },
+{"eorw", 4,    one(0005100),   one(0177700), "#w$s", m68000up },
+{"eorw", 4,    one(0005174),   one(0177777), "#wSs", m68000up },
+{"eorw", 2,    one(0130500),   one(0170700), "Dd$s", m68000up },
+{"eorl", 6,    one(0005200),   one(0177700), "#l$s", m68000up },
+{"eorl", 6,    one(0005200),   one(0177700), "#lDs", mcfisa_a },
+{"eorl", 2,    one(0130600),   one(0170700), "Dd$s", m68000up | mcfisa_a },
+{"eor", 4,     one(0005074),   one(0177777), "#bCs", m68000up },
+{"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 },
+{"exg", 2,     one(0140610),   one(0170770), "AsDd", m68000up },
+
+{"extw", 2,    one(0044200),   one(0177770), "Ds", m68000up|mcfisa_a },
+{"extl", 2,    one(0044300),   one(0177770), "Ds", m68000up|mcfisa_a },
+{"extbl", 2,   one(0044700),   one(0177770), "Ds", m68020up|cpu32|mcfisa_a },
+
+{"ff1", 2,     one(0002300), one(0177770), "Ds", mcfisa_aa},
+
+/* float stuff starts here */
+
+{"fabsb", 4,   two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fabsb", 4,   two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fabsd", 4,   two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fabsd", 4,   two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt", cfloat },
+{"fabsd", 4,   two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fabsd", 4,   two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fabsl", 4,   two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fabsl", 4,   two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fabsp", 4,   two(0xF000, 0x4C18), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fabss", 4,   two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7", cfloat },
+{"fabss", 4,   two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fabsw", 4,   two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fabsw", 4,   two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fabsx", 4,   two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fabsx", 4,   two(0xF000, 0x4818), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fabsx", 4,   two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fsabsb", 4,  two(0xF000, 0x5858), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fsabsb", 4,  two(0xF000, 0x5858), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsabsd", 4,  two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsabsd", 4,  two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiFt", cfloat },
+{"fsabsd", 4,  two(0xF000, 0x5458), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fsabsd", 4,  two(0xF000, 0x5458), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsabsl", 4,  two(0xF000, 0x4058), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fsabsl", 4,  two(0xF000, 0x4058), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsabsp", 4,  two(0xF000, 0x4C58), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fsabss", 4,  two(0xF000, 0x4258), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsabss", 4,  two(0xF000, 0x4458), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fsabsw", 4,  two(0xF000, 0x5058), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fsabsw", 4,  two(0xF000, 0x5058), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsabsx", 4,  two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fsabsx", 4,  two(0xF000, 0x4858), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fsabsx", 4,  two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiFt",   m68040up },
+
+{"fdabsb", 4,  two(0xF000, 0x585C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdabsb", 4,  two(0xF000, 0x585c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up},
+{"fdabsd", 4,  two(0xF000, 0x005C), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdabsd", 4,  two(0xF000, 0x005C), two(0xF1C0, 0xE07F), "IiFt", cfloat },
+{"fdabsd", 4,  two(0xF000, 0x545C), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fdabsd", 4,  two(0xF000, 0x545c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up},
+{"fdabsl", 4,  two(0xF000, 0x405C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdabsl", 4,  two(0xF000, 0x405c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up},
+{"fdabsp", 4,  two(0xF000, 0x4C5c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up},
+{"fdabss", 4,  two(0xF000, 0x425C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdabss", 4,  two(0xF000, 0x445c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up},
+{"fdabsw", 4,  two(0xF000, 0x505C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdabsw", 4,  two(0xF000, 0x505c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up},
+{"fdabsx", 4,  two(0xF000, 0x005c), two(0xF1C0, 0xE07F), "IiF8F7", m68040up},
+{"fdabsx", 4,  two(0xF000, 0x485c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up},
+{"fdabsx", 4,  two(0xF000, 0x005c), two(0xF1C0, 0xE07F), "IiFt",   m68040up},
+
+{"facosb", 4,  two(0xF000, 0x581C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"facosd", 4,  two(0xF000, 0x541C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"facosl", 4,  two(0xF000, 0x401C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"facosp", 4,  two(0xF000, 0x4C1C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"facoss", 4,  two(0xF000, 0x441C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"facosw", 4,  two(0xF000, 0x501C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"facosx", 4,  two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"facosx", 4,  two(0xF000, 0x481C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"facosx", 4,  two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"faddb", 4,   two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"faddb", 4,   two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"faddd", 4,   two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"faddd", 4,   two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"faddd", 4,   two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"faddd", 4,   two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"faddl", 4,   two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"faddl", 4,   two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"faddp", 4,   two(0xF000, 0x4C22), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fadds", 4,   two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fadds", 4,   two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"faddw", 4,   two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"faddw", 4,   two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"faddx", 4,   two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"faddx", 4,   two(0xF000, 0x4822), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+
+{"fsaddb", 4,  two(0xF000, 0x5862), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fsaddb", 4,  two(0xF000, 0x5862), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsaddd", 4,  two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsaddd", 4,  two(0xF000, 0x5462), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fsaddd", 4,  two(0xF000, 0x5462), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsaddl", 4,  two(0xF000, 0x4062), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fsaddl", 4,  two(0xF000, 0x4062), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsaddp", 4,  two(0xF000, 0x4C62), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fsadds", 4,  two(0xF000, 0x4462), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fsadds", 4,  two(0xF000, 0x4862), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsaddw", 4,  two(0xF000, 0x5062), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fsaddw", 4,  two(0xF000, 0x5062), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsaddx", 4,  two(0xF000, 0x0062), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fsaddx", 4,  two(0xF000, 0x4862), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+
+{"fdaddb", 4,  two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdaddb", 4,  two(0xF000, 0x5866), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fdaddd", 4,  two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdaddd", 4,  two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdaddd", 4,  two(0xF000, 0x5466), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fdaddl", 4,  two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fdaddl", 4,  two(0xF000, 0x4066), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fdaddp", 4,  two(0xF000, 0x4C66), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fdadds", 4,  two(0xF000, 0x4466), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fdadds", 4,  two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdaddw", 4,  two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdaddw", 4,  two(0xF000, 0x5066), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fdaddx", 4,  two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fdaddx", 4,  two(0xF000, 0x4866), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+
+{"fasinb", 4,  two(0xF000, 0x580C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fasind", 4,  two(0xF000, 0x540C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fasinl", 4,  two(0xF000, 0x400C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fasinp", 4,  two(0xF000, 0x4C0C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fasins", 4,  two(0xF000, 0x440C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fasinw", 4,  two(0xF000, 0x500C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fasinx", 4,  two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fasinx", 4,  two(0xF000, 0x480C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fasinx", 4,  two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fatanb", 4,  two(0xF000, 0x580A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fatand", 4,  two(0xF000, 0x540A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fatanl", 4,  two(0xF000, 0x400A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fatanp", 4,  two(0xF000, 0x4C0A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fatans", 4,  two(0xF000, 0x440A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fatanw", 4,  two(0xF000, 0x500A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fatanx", 4,  two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fatanx", 4,  two(0xF000, 0x480A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fatanx", 4,  two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fatanhb", 4, two(0xF000, 0x580D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fatanhd", 4, two(0xF000, 0x540D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fatanhl", 4, two(0xF000, 0x400D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fatanhp", 4, two(0xF000, 0x4C0D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fatanhs", 4, two(0xF000, 0x440D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fatanhw", 4, two(0xF000, 0x500D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fatanhx", 4, two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fatanhx", 4, two(0xF000, 0x480D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fatanhx", 4, two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fbeq", 2,    one(0xF081),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbf", 2,     one(0xF080),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbge", 2,    one(0xF093),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbgl", 2,    one(0xF096),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbgle", 2,   one(0xF097),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbgt", 2,    one(0xF092),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fble", 2,    one(0xF095),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fblt", 2,    one(0xF094),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbne", 2,    one(0xF08E),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbnge", 2,   one(0xF09C),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbngl", 2,   one(0xF099),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbngle", 2,  one(0xF098),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbngt", 2,   one(0xF09D),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbnle", 2,   one(0xF09A),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbnlt", 2,   one(0xF09B),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fboge", 2,   one(0xF083),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbogl", 2,   one(0xF086),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbogt", 2,   one(0xF082),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbole", 2,   one(0xF085),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbolt", 2,   one(0xF084),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbor", 2,    one(0xF087),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbseq", 2,   one(0xF091),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbsf", 2,    one(0xF090),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbsne", 2,   one(0xF09E),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbst", 2,    one(0xF09F),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbt", 2,     one(0xF08F),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbueq", 2,   one(0xF089),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbuge", 2,   one(0xF08B),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbugt", 2,   one(0xF08A),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbule", 2,   one(0xF08D),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbult", 2,   one(0xF08C),            one(0xF1FF), "IdBW", mfloat | cfloat },
+{"fbun", 2,    one(0xF088),            one(0xF1FF), "IdBW", mfloat | cfloat },
+
+{"fbeql", 2,   one(0xF0C1),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbfl", 2,    one(0xF0C0),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbgel", 2,   one(0xF0D3),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbgll", 2,   one(0xF0D6),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbglel", 2,  one(0xF0D7),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbgtl", 2,   one(0xF0D2),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fblel", 2,   one(0xF0D5),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbltl", 2,   one(0xF0D4),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbnel", 2,   one(0xF0CE),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbngel", 2,  one(0xF0DC),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbngll", 2,  one(0xF0D9),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbnglel", 2, one(0xF0D8),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbngtl", 2,  one(0xF0DD),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbnlel", 2,  one(0xF0DA),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbnltl", 2,  one(0xF0DB),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbogel", 2,  one(0xF0C3),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbogll", 2,  one(0xF0C6),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbogtl", 2,  one(0xF0C2),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbolel", 2,  one(0xF0C5),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fboltl", 2,  one(0xF0C4),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fborl", 2,   one(0xF0C7),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbseql", 2,  one(0xF0D1),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbsfl", 2,   one(0xF0D0),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbsnel", 2,  one(0xF0DE),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbstl", 2,   one(0xF0DF),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbtl", 2,    one(0xF0CF),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbueql", 2,  one(0xF0C9),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbugel", 2,  one(0xF0CB),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbugtl", 2,  one(0xF0CA),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbulel", 2,  one(0xF0CD),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbultl", 2,  one(0xF0CC),            one(0xF1FF), "IdBC", mfloat | cfloat },
+{"fbunl", 2,   one(0xF0C8),            one(0xF1FF), "IdBC", mfloat | cfloat },
+
+{"fjeq", 2,    one(0xF081),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjf", 2,     one(0xF080),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjge", 2,    one(0xF093),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjgl", 2,    one(0xF096),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjgle", 2,   one(0xF097),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjgt", 2,    one(0xF092),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjle", 2,    one(0xF095),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjlt", 2,    one(0xF094),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjne", 2,    one(0xF08E),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjnge", 2,   one(0xF09C),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjngl", 2,   one(0xF099),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjngle", 2,  one(0xF098),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjngt", 2,   one(0xF09D),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjnle", 2,   one(0xF09A),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjnlt", 2,   one(0xF09B),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjoge", 2,   one(0xF083),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjogl", 2,   one(0xF086),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjogt", 2,   one(0xF082),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjole", 2,   one(0xF085),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjolt", 2,   one(0xF084),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjor", 2,    one(0xF087),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjseq", 2,   one(0xF091),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjsf", 2,    one(0xF090),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjsne", 2,   one(0xF09E),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjst", 2,    one(0xF09F),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjt", 2,     one(0xF08F),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjueq", 2,   one(0xF089),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjuge", 2,   one(0xF08B),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjugt", 2,   one(0xF08A),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjule", 2,   one(0xF08D),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjult", 2,   one(0xF08C),            one(0xF1BF), "IdBc", mfloat | cfloat },
+{"fjun", 2,    one(0xF088),            one(0xF1BF), "IdBc", mfloat | cfloat },
+
+{"fcmpb", 4,   two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fcmpb", 4,   two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fcmpd", 4,   two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fcmpd", 4,   two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fcmpd", 4,   two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fcmpl", 4,   two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fcmpl", 4,   two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fcmpp", 4,   two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fcmps", 4,   two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fcmps", 4,   two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fcmpw", 4,   two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fcmpw", 4,   two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fcmpx", 4,   two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fcmpx", 4,   two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+
+{"fcosb", 4,   two(0xF000, 0x581D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fcosd", 4,   two(0xF000, 0x541D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fcosl", 4,   two(0xF000, 0x401D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fcosp", 4,   two(0xF000, 0x4C1D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fcoss", 4,   two(0xF000, 0x441D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fcosw", 4,   two(0xF000, 0x501D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fcosx", 4,   two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fcosx", 4,   two(0xF000, 0x481D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fcosx", 4,   two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fcoshb", 4,  two(0xF000, 0x5819), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fcoshd", 4,  two(0xF000, 0x5419), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fcoshl", 4,  two(0xF000, 0x4019), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fcoshp", 4,  two(0xF000, 0x4C19), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fcoshs", 4,  two(0xF000, 0x4419), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fcoshw", 4,  two(0xF000, 0x5019), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fcoshx", 4,  two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fcoshx", 4,  two(0xF000, 0x4819), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fcoshx", 4,  two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fdbeq", 4,   two(0xF048, 0x0001), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbf", 4,    two(0xF048, 0x0000), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbge", 4,   two(0xF048, 0x0013), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbgl", 4,   two(0xF048, 0x0016), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbgle", 4,  two(0xF048, 0x0017), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbgt", 4,   two(0xF048, 0x0012), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdble", 4,   two(0xF048, 0x0015), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdblt", 4,   two(0xF048, 0x0014), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbne", 4,   two(0xF048, 0x000E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbnge", 4,  two(0xF048, 0x001C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbngl", 4,  two(0xF048, 0x0019), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbngle", 4, two(0xF048, 0x0018), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbngt", 4,  two(0xF048, 0x001D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbnle", 4,  two(0xF048, 0x001A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbnlt", 4,  two(0xF048, 0x001B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdboge", 4,  two(0xF048, 0x0003), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbogl", 4,  two(0xF048, 0x0006), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbogt", 4,  two(0xF048, 0x0002), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbole", 4,  two(0xF048, 0x0005), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbolt", 4,  two(0xF048, 0x0004), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbor", 4,   two(0xF048, 0x0007), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbseq", 4,  two(0xF048, 0x0011), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbsf", 4,   two(0xF048, 0x0010), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbsne", 4,  two(0xF048, 0x001E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbst", 4,   two(0xF048, 0x001F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbt", 4,    two(0xF048, 0x000F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbueq", 4,  two(0xF048, 0x0009), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbuge", 4,  two(0xF048, 0x000B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbugt", 4,  two(0xF048, 0x000A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbule", 4,  two(0xF048, 0x000D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbult", 4,  two(0xF048, 0x000C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+{"fdbun", 4,   two(0xF048, 0x0008), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
+
+{"fdivb", 4,   two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fdivb", 4,   two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdivd", 4,   two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdivd", 4,   two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fdivd", 4,   two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fdivl", 4,   two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fdivl", 4,   two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdivp", 4,   two(0xF000, 0x4C20), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fdivs", 4,   two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fdivs", 4,   two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdivw", 4,   two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fdivw", 4,   two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdivx", 4,   two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fdivx", 4,   two(0xF000, 0x4820), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+
+{"fsdivb", 4,  two(0xF000, 0x5860), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fsdivb", 4,  two(0xF000, 0x5860), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsdivd", 4,  two(0xF000, 0x0060), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsdivd", 4,  two(0xF000, 0x5460), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fsdivd", 4,  two(0xF000, 0x5460), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsdivl", 4,  two(0xF000, 0x4060), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fsdivl", 4,  two(0xF000, 0x4060), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsdivp", 4,  two(0xF000, 0x4C60), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fsdivs", 4,  two(0xF000, 0x4460), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fsdivs", 4,  two(0xF000, 0x4460), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsdivw", 4,  two(0xF000, 0x5060), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fsdivw", 4,  two(0xF000, 0x5060), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsdivx", 4,  two(0xF000, 0x0060), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fsdivx", 4,  two(0xF000, 0x4860), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+
+{"fddivb", 4,  two(0xF000, 0x5864), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fddivb", 4,  two(0xF000, 0x5864), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fddivd", 4,  two(0xF000, 0x0064), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fddivd", 4,  two(0xF000, 0x5464), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fddivd", 4,  two(0xF000, 0x5464), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fddivl", 4,  two(0xF000, 0x4064), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fddivl", 4,  two(0xF000, 0x4064), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fddivp", 4,  two(0xF000, 0x4C64), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fddivs", 4,  two(0xF000, 0x4464), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fddivs", 4,  two(0xF000, 0x4464), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fddivw", 4,  two(0xF000, 0x5064), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fddivw", 4,  two(0xF000, 0x5064), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fddivx", 4,  two(0xF000, 0x0064), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fddivx", 4,  two(0xF000, 0x4864), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+
+{"fetoxb", 4,  two(0xF000, 0x5810), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fetoxd", 4,  two(0xF000, 0x5410), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fetoxl", 4,  two(0xF000, 0x4010), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fetoxp", 4,  two(0xF000, 0x4C10), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fetoxs", 4,  two(0xF000, 0x4410), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fetoxw", 4,  two(0xF000, 0x5010), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fetoxx", 4,  two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fetoxx", 4,  two(0xF000, 0x4810), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fetoxx", 4,  two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fetoxm1b", 4,        two(0xF000, 0x5808), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fetoxm1d", 4,        two(0xF000, 0x5408), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fetoxm1l", 4,        two(0xF000, 0x4008), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fetoxm1p", 4,        two(0xF000, 0x4C08), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fetoxm1s", 4,        two(0xF000, 0x4408), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fetoxm1w", 4,        two(0xF000, 0x5008), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fetoxm1x", 4,        two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fetoxm1x", 4,        two(0xF000, 0x4808), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fetoxm1x", 4,        two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fgetexpb", 4,        two(0xF000, 0x581E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fgetexpd", 4,        two(0xF000, 0x541E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fgetexpl", 4,        two(0xF000, 0x401E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fgetexpp", 4,        two(0xF000, 0x4C1E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fgetexps", 4,        two(0xF000, 0x441E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fgetexpw", 4,        two(0xF000, 0x501E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fgetexpx", 4,        two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fgetexpx", 4,        two(0xF000, 0x481E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fgetexpx", 4,        two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fgetmanb", 4,        two(0xF000, 0x581F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fgetmand", 4,        two(0xF000, 0x541F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fgetmanl", 4,        two(0xF000, 0x401F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fgetmanp", 4,        two(0xF000, 0x4C1F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fgetmans", 4,        two(0xF000, 0x441F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fgetmanw", 4,        two(0xF000, 0x501F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fgetmanx", 4,        two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fgetmanx", 4,        two(0xF000, 0x481F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fgetmanx", 4,        two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fintb", 4,   two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fintb", 4,   two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintd", 4,   two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fintd", 4,   two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt", cfloat },
+{"fintd", 4,   two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fintd", 4,   two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fintl", 4,   two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fintl", 4,   two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintp", 4,   two(0xF000, 0x4C01), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fints", 4,   two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fints", 4,   two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintw", 4,   two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fintw", 4,   two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintx", 4,   two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fintx", 4,   two(0xF000, 0x4801), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fintx", 4,   two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fintrzb", 4, two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fintrzb", 4, two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintrzd", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fintrzd", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt",   cfloat },
+{"fintrzd", 4, two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fintrzd", 4, two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fintrzl", 4, two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fintrzl", 4, two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintrzp", 4, two(0xF000, 0x4C03), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fintrzs", 4, two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fintrzs", 4, two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintrzw", 4, two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fintrzw", 4, two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fintrzx", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fintrzx", 4, two(0xF000, 0x4803), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fintrzx", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"flog10b", 4, two(0xF000, 0x5815), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"flog10d", 4, two(0xF000, 0x5415), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"flog10l", 4, two(0xF000, 0x4015), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"flog10p", 4, two(0xF000, 0x4C15), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"flog10s", 4, two(0xF000, 0x4415), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"flog10w", 4, two(0xF000, 0x5015), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"flog10x", 4, two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"flog10x", 4, two(0xF000, 0x4815), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"flog10x", 4, two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"flog2b", 4,  two(0xF000, 0x5816), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"flog2d", 4,  two(0xF000, 0x5416), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"flog2l", 4,  two(0xF000, 0x4016), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"flog2p", 4,  two(0xF000, 0x4C16), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"flog2s", 4,  two(0xF000, 0x4416), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"flog2w", 4,  two(0xF000, 0x5016), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"flog2x", 4,  two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"flog2x", 4,  two(0xF000, 0x4816), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"flog2x", 4,  two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"flognb", 4,  two(0xF000, 0x5814), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"flognd", 4,  two(0xF000, 0x5414), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"flognl", 4,  two(0xF000, 0x4014), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"flognp", 4,  two(0xF000, 0x4C14), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"flogns", 4,  two(0xF000, 0x4414), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"flognw", 4,  two(0xF000, 0x5014), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"flognx", 4,  two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"flognx", 4,  two(0xF000, 0x4814), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"flognx", 4,  two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"flognp1b", 4,        two(0xF000, 0x5806), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"flognp1d", 4,        two(0xF000, 0x5406), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"flognp1l", 4,        two(0xF000, 0x4006), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"flognp1p", 4,        two(0xF000, 0x4C06), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"flognp1s", 4,        two(0xF000, 0x4406), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"flognp1w", 4,        two(0xF000, 0x5006), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"flognp1x", 4,        two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"flognp1x", 4,        two(0xF000, 0x4806), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"flognp1x", 4,        two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fmodb", 4,   two(0xF000, 0x5821), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fmodd", 4,   two(0xF000, 0x5421), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fmodl", 4,   two(0xF000, 0x4021), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fmodp", 4,   two(0xF000, 0x4C21), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fmods", 4,   two(0xF000, 0x4421), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fmodw", 4,   two(0xF000, 0x5021), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fmodx", 4,   two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fmodx", 4,   two(0xF000, 0x4821), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+
+{"fmoveb", 4,  two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmoveb", 4,  two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7bs", cfloat },
+{"fmoveb", 4,  two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fmoveb", 4,  two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7$b", mfloat },
+{"fmoved", 4,  two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fmoved", 4,  two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7~F", mfloat },
+{"fmoved", 4,  two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fmoved", 4,  two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fmoved", 4,  two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7ws", cfloat },
+{"fmovel", 4,  two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fmovel", 4,  two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7$l", mfloat },
+/* FIXME: the next two variants should not permit moving an address
+   register to anything but the floating point instruction register.  */
+{"fmovel", 4,  two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat },
+{"fmovel", 4,  two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ls8", mfloat },
+{"fmovel", 4,  two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmovel", 4,  two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7bs", cfloat },
+  /* Move the FP control registers.  */
+{"fmovel", 4,  two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8ps", cfloat },
+{"fmovel", 4,  two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Iibss8", cfloat },
+{"fmovep", 4,  two(0xF000, 0x4C00), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fmovep", 4,  two(0xF000, 0x6C00), two(0xF1C0, 0xFC00), "IiF7~pkC", mfloat },
+{"fmovep", 4,  two(0xF000, 0x7C00), two(0xF1C0, 0xFC0F), "IiF7~pDk", mfloat },
+{"fmoves", 4,  two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fmoves", 4,  two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7$f", mfloat },
+{"fmoves", 4,  two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmoves", 4,  two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fmovew", 4,  two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fmovew", 4,  two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7$w", mfloat },
+{"fmovew", 4,  two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmovew", 4,  two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fmovex", 4,  two(0xF000, 0x0000), two(0xF1FF, 0xE07F), "IiF8F7", mfloat },
+{"fmovex", 4,  two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fmovex", 4,  two(0xF000, 0x6800), two(0xF1C0, 0xFC7F), "IiF7~x", mfloat },
+
+{"fsmoveb", 4, two(0xF000, 0x5840), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fsmoveb", 4, two(0xF000, 0x5840), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmoveb", 4, two(0xF000, 0x7840), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fsmoved", 4, two(0xF000, 0x0040), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsmoved", 4, two(0xF000, 0x5440), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fsmoved", 4, two(0xF000, 0x5440), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsmoved", 4, two(0xF000, 0x7440), two(0xF1C0, 0xFC7F), "IiF7ws", cfloat },
+{"fsmovel", 4, two(0xF000, 0x4040), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fsmovel", 4, two(0xF000, 0x4040), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmovel", 4, two(0xF000, 0x6040), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fsmoves", 4, two(0xF000, 0x4440), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fsmoves", 4, two(0xF000, 0x4440), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmoves", 4, two(0xF000, 0x6440), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fsmovew", 4, two(0xF000, 0x5040), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fsmovew", 4, two(0xF000, 0x5040), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmovew", 4, two(0xF000, 0x7040), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fsmovex", 4, two(0xF000, 0x0040), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fsmovex", 4, two(0xF000, 0x4840), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fsmovep", 4, two(0xF000, 0x4C40), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+
+{"fdmoveb", 4, two(0xF000, 0x5844), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fdmoveb", 4, two(0xF000, 0x5844), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmoveb", 4, two(0xF000, 0x7844), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fdmoved", 4, two(0xF000, 0x0044), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdmoved", 4, two(0xF000, 0x5444), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fdmoved", 4, two(0xF000, 0x5444), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fdmoved", 4, two(0xF000, 0x7444), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fdmovel", 4, two(0xF000, 0x4044), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fdmovel", 4, two(0xF000, 0x4044), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmovel", 4, two(0xF000, 0x6044), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fdmoves", 4, two(0xF000, 0x4444), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fdmoves", 4, two(0xF000, 0x4444), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmoves", 4, two(0xF000, 0x6444), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fdmovew", 4, two(0xF000, 0x5044), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fdmovew", 4, two(0xF000, 0x5044), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmovew", 4, two(0xF000, 0x7044), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
+{"fdmovex", 4, two(0xF000, 0x0044), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fdmovex", 4, two(0xF000, 0x4844), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fdmovep", 4, two(0xF000, 0x4C44), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+
+{"fmovecrx", 4,        two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7", mfloat },
+
+{"fmovemd", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizsl3", cfloat },
+{"fmovemd", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizs#3", cfloat },
+{"fmovemd", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Ii#3ys", cfloat },
+{"fmovemd", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Iil3ys", cfloat },
+
+{"fmovemx", 4, two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat },
+{"fmovemx", 4, two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat },
+{"fmovemx", 4, two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat },
+{"fmovemx", 4, two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat },
+{"fmovemx", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat },
+{"fmovemx", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat },
+{"fmovemx", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat },
+{"fmovemx", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat },
+{"fmovemx", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat },
+{"fmovemx", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat },
+{"fmovemx", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat },
+{"fmovemx", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat },
+
+{"fmoveml", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat },
+{"fmoveml", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8~s", mfloat },
+/* FIXME: In the next instruction, we should only permit %dn if the
+   target is a single register.  We should only permit %an if the
+   target is a single %fpiar.  */
+{"fmoveml", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*lL8", mfloat },
+
+{"fmovem", 4,  two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "IizsL3", cfloat },
+{"fmovem", 4,  two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizs#3", cfloat },
+{"fmovem", 4,  two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Ii#3ys", cfloat },
+{"fmovem", 4,  two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "IiL3ys", cfloat },
+
+{"fmovem", 4,  two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat },
+{"fmovem", 4,  two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat },
+{"fmovem", 4,  two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat },
+{"fmovem", 4,  two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat },
+{"fmovem", 4,  two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat },
+{"fmovem", 4,  two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat },
+{"fmovem", 4,  two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat },
+{"fmovem", 4,  two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat },
+{"fmovem", 4,  two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat },
+{"fmovem", 4,  two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat },
+{"fmovem", 4,  two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat },
+{"fmovem", 4,  two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat },
+{"fmovem", 4,  two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat },
+{"fmovem", 4,  two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ss8", mfloat },
+{"fmovem", 4,  two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8~s", mfloat },
+{"fmovem", 4,  two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*sL8", mfloat },
+
+{"fmulb", 4,   two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fmulb", 4,   two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmuld", 4,   two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fmuld", 4,   two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fmuld", 4,   two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fmull", 4,   two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fmull", 4,   two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmulp", 4,   two(0xF000, 0x4C23), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fmuls", 4,   two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fmuls", 4,   two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmulw", 4,   two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fmulw", 4,   two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fmulx", 4,   two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fmulx", 4,   two(0xF000, 0x4823), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+
+{"fsmulb", 4,  two(0xF000, 0x5863), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fsmulb", 4,  two(0xF000, 0x5863), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmuld", 4,  two(0xF000, 0x0063), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsmuld", 4,  two(0xF000, 0x5463), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fsmuld", 4,  two(0xF000, 0x5463), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsmull", 4,  two(0xF000, 0x4063), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fsmull", 4,  two(0xF000, 0x4063), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmulp", 4,  two(0xF000, 0x4C63), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fsmuls", 4,  two(0xF000, 0x4463), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fsmuls", 4,  two(0xF000, 0x4463), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmulw", 4,  two(0xF000, 0x5063), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fsmulw", 4,  two(0xF000, 0x5063), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsmulx", 4,  two(0xF000, 0x0063), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fsmulx", 4,  two(0xF000, 0x4863), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+
+{"fdmulb", 4,  two(0xF000, 0x5867), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fdmulb", 4,  two(0xF000, 0x5867), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmuld", 4,  two(0xF000, 0x0067), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdmuld", 4,  two(0xF000, 0x5467), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fdmuld", 4,  two(0xF000, 0x5467), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fdmull", 4,  two(0xF000, 0x4067), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fdmull", 4,  two(0xF000, 0x4067), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmulp", 4,  two(0xF000, 0x4C67), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fdmuls", 4,  two(0xF000, 0x4467), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fdmuls", 4,  two(0xF000, 0x4467), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmulw", 4,  two(0xF000, 0x5067), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fdmulw", 4,  two(0xF000, 0x5067), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdmulx", 4,  two(0xF000, 0x0067), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fdmulx", 4,  two(0xF000, 0x4867), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+
+{"fnegb", 4,   two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fnegb", 4,   two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fnegd", 4,   two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fnegd", 4,   two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt",   cfloat },
+{"fnegd", 4,   two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fnegd", 4,   two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fnegl", 4,   two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fnegl", 4,   two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fnegp", 4,   two(0xF000, 0x4C1A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fnegs", 4,   two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fnegs", 4,   two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fnegw", 4,   two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fnegw", 4,   two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fnegx", 4,   two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fnegx", 4,   two(0xF000, 0x481A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fnegx", 4,   two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fsnegb", 4,  two(0xF000, 0x585A), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fsnegb", 4,  two(0xF000, 0x585A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsnegd", 4,  two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsnegd", 4,  two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiFt",   cfloat },
+{"fsnegd", 4,  two(0xF000, 0x545A), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fsnegd", 4,  two(0xF000, 0x545A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsnegl", 4,  two(0xF000, 0x405A), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fsnegl", 4,  two(0xF000, 0x405A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsnegp", 4,  two(0xF000, 0x4C5A), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fsnegs", 4,  two(0xF000, 0x445A), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fsnegs", 4,  two(0xF000, 0x445A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsnegw", 4,  two(0xF000, 0x505A), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fsnegw", 4,  two(0xF000, 0x505A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsnegx", 4,  two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fsnegx", 4,  two(0xF000, 0x485A), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fsnegx", 4,  two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiFt",   m68040up },
+
+{"fdnegb", 4,  two(0xF000, 0x585E), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fdnegb", 4,  two(0xF000, 0x585E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdnegd", 4,  two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdnegd", 4,  two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiFt",   cfloat },
+{"fdnegd", 4,  two(0xF000, 0x545E), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fdnegd", 4,  two(0xF000, 0x545E), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fdnegl", 4,  two(0xF000, 0x405E), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fdnegl", 4,  two(0xF000, 0x405E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdnegp", 4,  two(0xF000, 0x4C5E), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fdnegs", 4,  two(0xF000, 0x445E), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fdnegs", 4,  two(0xF000, 0x445E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdnegw", 4,  two(0xF000, 0x505E), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fdnegw", 4,  two(0xF000, 0x505E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdnegx", 4,  two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fdnegx", 4,  two(0xF000, 0x485E), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fdnegx", 4,  two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiFt",   m68040up },
+
+{"fnop", 4,    two(0xF280, 0x0000), two(0xFFFF, 0xFFFF), "Ii", mfloat | cfloat },
+
+{"fremb", 4,   two(0xF000, 0x5825), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fremd", 4,   two(0xF000, 0x5425), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"freml", 4,   two(0xF000, 0x4025), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fremp", 4,   two(0xF000, 0x4C25), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"frems", 4,   two(0xF000, 0x4425), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fremw", 4,   two(0xF000, 0x5025), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fremx", 4,   two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fremx", 4,   two(0xF000, 0x4825), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+
+{"frestore", 2,        one(0xF140),            one(0xF1C0), "Id<s", mfloat },
+{"frestore", 2,        one(0xF140),            one(0xF1C0), "Idys", cfloat },
+
+{"fsave", 2,   one(0xF100),            one(0xF1C0), "Id>s", mfloat },
+{"fsave", 2,   one(0xF100),            one(0xF1C0), "Idzs", cfloat },
+
+{"fscaleb", 4, two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fscaled", 4, two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fscalel", 4, two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fscalep", 4, two(0xF000, 0x4C26), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fscales", 4, two(0xF000, 0x4426), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fscalew", 4, two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fscalex", 4, two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fscalex", 4, two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+
+/* $ is necessary to prevent the assembler from using PC-relative.
+   If @ were used, "label: fseq label" could produce "ftrapeq", 2,
+   because "label" became "pc@label".  */
+{"fseq", 4,    two(0xF040, 0x0001), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsf", 4,     two(0xF040, 0x0000), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsge", 4,    two(0xF040, 0x0013), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsgl", 4,    two(0xF040, 0x0016), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsgle", 4,   two(0xF040, 0x0017), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsgt", 4,    two(0xF040, 0x0012), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsle", 4,    two(0xF040, 0x0015), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fslt", 4,    two(0xF040, 0x0014), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsne", 4,    two(0xF040, 0x000E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsnge", 4,   two(0xF040, 0x001C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsngl", 4,   two(0xF040, 0x0019), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsngle", 4,  two(0xF040, 0x0018), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsngt", 4,   two(0xF040, 0x001D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsnle", 4,   two(0xF040, 0x001A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsnlt", 4,   two(0xF040, 0x001B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsoge", 4,   two(0xF040, 0x0003), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsogl", 4,   two(0xF040, 0x0006), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsogt", 4,   two(0xF040, 0x0002), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsole", 4,   two(0xF040, 0x0005), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsolt", 4,   two(0xF040, 0x0004), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsor", 4,    two(0xF040, 0x0007), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsseq", 4,   two(0xF040, 0x0011), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fssf", 4,    two(0xF040, 0x0010), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fssne", 4,   two(0xF040, 0x001E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsst", 4,    two(0xF040, 0x001F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fst", 4,     two(0xF040, 0x000F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsueq", 4,   two(0xF040, 0x0009), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsuge", 4,   two(0xF040, 0x000B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsugt", 4,   two(0xF040, 0x000A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsule", 4,   two(0xF040, 0x000D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsult", 4,   two(0xF040, 0x000C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+{"fsun", 4,    two(0xF040, 0x0008), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
+
+{"fsgldivb", 4,        two(0xF000, 0x5824), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsgldivd", 4,        two(0xF000, 0x5424), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsgldivl", 4,        two(0xF000, 0x4024), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsgldivp", 4,        two(0xF000, 0x4C24), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsgldivs", 4,        two(0xF000, 0x4424), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsgldivw", 4,        two(0xF000, 0x5024), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsgldivx", 4,        two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsgldivx", 4,        two(0xF000, 0x4824), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsgldivx", 4,        two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fsglmulb", 4,        two(0xF000, 0x5827), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsglmuld", 4,        two(0xF000, 0x5427), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsglmull", 4,        two(0xF000, 0x4027), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsglmulp", 4,        two(0xF000, 0x4C27), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsglmuls", 4,        two(0xF000, 0x4427), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsglmulw", 4,        two(0xF000, 0x5027), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsglmulx", 4,        two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsglmulx", 4,        two(0xF000, 0x4827), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsglmulx", 4,        two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fsinb", 4,   two(0xF000, 0x580E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsind", 4,   two(0xF000, 0x540E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsinl", 4,   two(0xF000, 0x400E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsinp", 4,   two(0xF000, 0x4C0E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsins", 4,   two(0xF000, 0x440E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsinw", 4,   two(0xF000, 0x500E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsinx", 4,   two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsinx", 4,   two(0xF000, 0x480E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsinx", 4,   two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fsincosb", 4,        two(0xF000, 0x5830), two(0xF1C0, 0xFC78), "Ii;bF3F7", mfloat },
+{"fsincosd", 4,        two(0xF000, 0x5430), two(0xF1C0, 0xFC78), "Ii;FF3F7", mfloat },
+{"fsincosl", 4,        two(0xF000, 0x4030), two(0xF1C0, 0xFC78), "Ii;lF3F7", mfloat },
+{"fsincosp", 4,        two(0xF000, 0x4C30), two(0xF1C0, 0xFC78), "Ii;pF3F7", mfloat },
+{"fsincoss", 4,        two(0xF000, 0x4430), two(0xF1C0, 0xFC78), "Ii;fF3F7", mfloat },
+{"fsincosw", 4,        two(0xF000, 0x5030), two(0xF1C0, 0xFC78), "Ii;wF3F7", mfloat },
+{"fsincosx", 4,        two(0xF000, 0x0030), two(0xF1C0, 0xE078), "IiF8F3F7", mfloat },
+{"fsincosx", 4,        two(0xF000, 0x4830), two(0xF1C0, 0xFC78), "Ii;xF3F7", mfloat },
+
+{"fsinhb", 4,  two(0xF000, 0x5802), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsinhd", 4,  two(0xF000, 0x5402), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsinhl", 4,  two(0xF000, 0x4002), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsinhp", 4,  two(0xF000, 0x4C02), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsinhs", 4,  two(0xF000, 0x4402), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsinhw", 4,  two(0xF000, 0x5002), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsinhx", 4,  two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsinhx", 4,  two(0xF000, 0x4802), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsinhx", 4,  two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fsqrtb", 4,  two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsqrtb", 4,  two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsqrtd", 4,  two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsqrtd", 4,  two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt",   cfloat },
+{"fsqrtd", 4,  two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsqrtd", 4,  two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsqrtl", 4,  two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsqrtl", 4,  two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsqrtp", 4,  two(0xF000, 0x4C04), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsqrts", 4,  two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsqrts", 4,  two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsqrtw", 4,  two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsqrtw", 4,  two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsqrtx", 4,  two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsqrtx", 4,  two(0xF000, 0x4804), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsqrtx", 4,  two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fssqrtb", 4, two(0xF000, 0x5841), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fssqrtb", 4, two(0xF000, 0x5841), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssqrtd", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fssqrtd", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiFt",   cfloat },
+{"fssqrtd", 4, two(0xF000, 0x5441), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fssqrtd", 4, two(0xF000, 0x5441), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fssqrtl", 4, two(0xF000, 0x4041), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fssqrtl", 4, two(0xF000, 0x4041), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssqrtp", 4, two(0xF000, 0x4C41), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fssqrts", 4, two(0xF000, 0x4441), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fssqrts", 4, two(0xF000, 0x4441), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssqrtw", 4, two(0xF000, 0x5041), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fssqrtw", 4, two(0xF000, 0x5041), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssqrtx", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fssqrtx", 4, two(0xF000, 0x4841), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fssqrtx", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiFt",   m68040up },
+
+{"fdsqrtb", 4, two(0xF000, 0x5845), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fdsqrtb", 4, two(0xF000, 0x5845), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsqrtd", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdsqrtd", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiFt",   cfloat },
+{"fdsqrtd", 4, two(0xF000, 0x5445), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fdsqrtl", 4, two(0xF000, 0x4045), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fdsqrtl", 4, two(0xF000, 0x4045), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsqrtp", 4, two(0xF000, 0x4C45), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fdsqrts", 4, two(0xF000, 0x4445), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fdsqrts", 4, two(0xF000, 0x4445), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsqrtw", 4, two(0xF000, 0x5045), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fdsqrtw", 4, two(0xF000, 0x5045), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsqrtx", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fdsqrtx", 4, two(0xF000, 0x4845), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fdsqrtx", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiFt",   m68040up },
+
+{"fsubb", 4,   two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"fsubb", 4,   two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsubd", 4,   two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fsubd", 4,   two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"fsubd", 4,   two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fsubl", 4,   two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"fsubl", 4,   two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsubp", 4,   two(0xF000, 0x4C28), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"fsubs", 4,   two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"fsubs", 4,   two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsubw", 4,   two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"fsubw", 4,   two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fsubx", 4,   two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"fsubx", 4,   two(0xF000, 0x4828), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"fsubx", 4,   two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"fssubb", 4,  two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssubb", 4,  two(0xF000, 0x5868), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fssubd", 4,  two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fssubd", 4,  two(0xF000, 0x5468), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fssubd", 4,  two(0xF000, 0x5468), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fssubl", 4,  two(0xF000, 0x4068), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fssubl", 4,  two(0xF000, 0x4068), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssubp", 4,  two(0xF000, 0x4C68), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fssubs", 4,  two(0xF000, 0x4468), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fssubs", 4,  two(0xF000, 0x4468), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssubw", 4,  two(0xF000, 0x5068), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fssubw", 4,  two(0xF000, 0x5068), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fssubx", 4,  two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fssubx", 4,  two(0xF000, 0x4868), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fssubx", 4,  two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiFt",   m68040up },
+
+{"fdsubb", 4,  two(0xF000, 0x586A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsubb", 4,  two(0xF000, 0x586c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
+{"fdsubd", 4,  two(0xF000, 0x006A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
+{"fdsubd", 4,  two(0xF000, 0x546A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
+{"fdsubd", 4,  two(0xF000, 0x546c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
+{"fdsubl", 4,  two(0xF000, 0x406A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsubl", 4,  two(0xF000, 0x406c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
+{"fdsubp", 4,  two(0xF000, 0x4C6c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
+{"fdsubs", 4,  two(0xF000, 0x446A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsubs", 4,  two(0xF000, 0x446c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
+{"fdsubw", 4,  two(0xF000, 0x506A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
+{"fdsubw", 4,  two(0xF000, 0x506c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
+{"fdsubx", 4,  two(0xF000, 0x006c), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
+{"fdsubx", 4,  two(0xF000, 0x486c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
+{"fdsubx", 4,  two(0xF000, 0x006c), two(0xF1C0, 0xE07F), "IiFt",   m68040up },
+
+{"ftanb", 4,   two(0xF000, 0x580F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"ftand", 4,   two(0xF000, 0x540F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"ftanl", 4,   two(0xF000, 0x400F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"ftanp", 4,   two(0xF000, 0x4C0F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"ftans", 4,   two(0xF000, 0x440F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"ftanw", 4,   two(0xF000, 0x500F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"ftanx", 4,   two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"ftanx", 4,   two(0xF000, 0x480F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"ftanx", 4,   two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"ftanhb", 4,  two(0xF000, 0x5809), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"ftanhd", 4,  two(0xF000, 0x5409), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"ftanhl", 4,  two(0xF000, 0x4009), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"ftanhp", 4,  two(0xF000, 0x4C09), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"ftanhs", 4,  two(0xF000, 0x4409), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"ftanhw", 4,  two(0xF000, 0x5009), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"ftanhx", 4,  two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"ftanhx", 4,  two(0xF000, 0x4809), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"ftanhx", 4,  two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"ftentoxb", 4,        two(0xF000, 0x5812), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"ftentoxd", 4,        two(0xF000, 0x5412), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"ftentoxl", 4,        two(0xF000, 0x4012), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"ftentoxp", 4,        two(0xF000, 0x4C12), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"ftentoxs", 4,        two(0xF000, 0x4412), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"ftentoxw", 4,        two(0xF000, 0x5012), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"ftentoxx", 4,        two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"ftentoxx", 4,        two(0xF000, 0x4812), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"ftentoxx", 4,        two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"ftrapeq", 4, two(0xF07C, 0x0001), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapf", 4,  two(0xF07C, 0x0000), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapge", 4, two(0xF07C, 0x0013), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapgl", 4, two(0xF07C, 0x0016), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapgle", 4,        two(0xF07C, 0x0017), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapgt", 4, two(0xF07C, 0x0012), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftraple", 4, two(0xF07C, 0x0015), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftraplt", 4, two(0xF07C, 0x0014), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapne", 4, two(0xF07C, 0x000E), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapnge", 4,        two(0xF07C, 0x001C), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapngl", 4,        two(0xF07C, 0x0019), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapngle", 4,two(0xF07C, 0x0018), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapngt", 4,        two(0xF07C, 0x001D), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapnle", 4,        two(0xF07C, 0x001A), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapnlt", 4,        two(0xF07C, 0x001B), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapoge", 4,        two(0xF07C, 0x0003), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapogl", 4,        two(0xF07C, 0x0006), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapogt", 4,        two(0xF07C, 0x0002), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapole", 4,        two(0xF07C, 0x0005), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapolt", 4,        two(0xF07C, 0x0004), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapor", 4, two(0xF07C, 0x0007), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapseq", 4,        two(0xF07C, 0x0011), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapsf", 4, two(0xF07C, 0x0010), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapsne", 4,        two(0xF07C, 0x001E), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapst", 4, two(0xF07C, 0x001F), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapt", 4,  two(0xF07C, 0x000F), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapueq", 4,        two(0xF07C, 0x0009), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapuge", 4,        two(0xF07C, 0x000B), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapugt", 4,        two(0xF07C, 0x000A), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapule", 4,        two(0xF07C, 0x000D), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapult", 4,        two(0xF07C, 0x000C), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+{"ftrapun", 4, two(0xF07C, 0x0008), two(0xF1FF, 0xFFFF), "Ii", mfloat },
+
+{"ftrapeqw", 4,        two(0xF07A, 0x0001), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapfw", 4, two(0xF07A, 0x0000), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapgew", 4,        two(0xF07A, 0x0013), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapglw", 4,        two(0xF07A, 0x0016), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapglew", 4,two(0xF07A, 0x0017), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapgtw", 4,        two(0xF07A, 0x0012), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftraplew", 4,        two(0xF07A, 0x0015), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapltw", 4,        two(0xF07A, 0x0014), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnew", 4,        two(0xF07A, 0x000E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapngew", 4,two(0xF07A, 0x001C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnglw", 4,two(0xF07A, 0x0019), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnglew", 4,two(0xF07A, 0x0018), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapngtw", 4,two(0xF07A, 0x001D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnlew", 4,two(0xF07A, 0x001A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapnltw", 4,two(0xF07A, 0x001B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapogew", 4,two(0xF07A, 0x0003), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapoglw", 4,two(0xF07A, 0x0006), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapogtw", 4,two(0xF07A, 0x0002), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapolew", 4,two(0xF07A, 0x0005), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapoltw", 4,two(0xF07A, 0x0004), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftraporw", 4,        two(0xF07A, 0x0007), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapseqw", 4,two(0xF07A, 0x0011), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapsfw", 4,        two(0xF07A, 0x0010), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapsnew", 4,two(0xF07A, 0x001E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapstw", 4,        two(0xF07A, 0x001F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftraptw", 4, two(0xF07A, 0x000F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapueqw", 4,two(0xF07A, 0x0009), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapugew", 4,two(0xF07A, 0x000B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapugtw", 4,two(0xF07A, 0x000A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapulew", 4,two(0xF07A, 0x000D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapultw", 4,two(0xF07A, 0x000C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+{"ftrapunw", 4,        two(0xF07A, 0x0008), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
+
+{"ftrapeql", 4,        two(0xF07B, 0x0001), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapfl", 4, two(0xF07B, 0x0000), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapgel", 4,        two(0xF07B, 0x0013), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapgll", 4,        two(0xF07B, 0x0016), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapglel", 4,two(0xF07B, 0x0017), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapgtl", 4,        two(0xF07B, 0x0012), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftraplel", 4,        two(0xF07B, 0x0015), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapltl", 4,        two(0xF07B, 0x0014), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapnel", 4,        two(0xF07B, 0x000E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapngel", 4,two(0xF07B, 0x001C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapngll", 4,two(0xF07B, 0x0019), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapnglel", 4,two(0xF07B, 0x0018), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapngtl", 4,two(0xF07B, 0x001D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapnlel", 4,two(0xF07B, 0x001A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapnltl", 4,two(0xF07B, 0x001B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapogel", 4,two(0xF07B, 0x0003), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapogll", 4,two(0xF07B, 0x0006), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapogtl", 4,two(0xF07B, 0x0002), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapolel", 4,two(0xF07B, 0x0005), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapoltl", 4,two(0xF07B, 0x0004), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftraporl", 4,        two(0xF07B, 0x0007), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapseql", 4,two(0xF07B, 0x0011), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapsfl", 4,        two(0xF07B, 0x0010), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapsnel", 4,two(0xF07B, 0x001E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapstl", 4,        two(0xF07B, 0x001F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftraptl", 4, two(0xF07B, 0x000F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapueql", 4,two(0xF07B, 0x0009), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapugel", 4,two(0xF07B, 0x000B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapugtl", 4,two(0xF07B, 0x000A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapulel", 4,two(0xF07B, 0x000D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapultl", 4,two(0xF07B, 0x000C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+{"ftrapunl", 4,        two(0xF07B, 0x0008), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
+
+{"ftstb", 4,   two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Ii;b", mfloat },
+{"ftstb", 4,   two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
+{"ftstd", 4,   two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8", cfloat },
+{"ftstd", 4,   two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Ii;F", mfloat },
+{"ftstd", 4,   two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
+{"ftstl", 4,   two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Ii;l", mfloat },
+{"ftstl", 4,   two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
+{"ftstp", 4,   two(0xF000, 0x4C3A), two(0xF1C0, 0xFC7F), "Ii;p", mfloat },
+{"ftsts", 4,   two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Ii;f", mfloat },
+{"ftsts", 4,   two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
+{"ftstw", 4,   two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Ii;w", mfloat },
+{"ftstw", 4,   two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
+{"ftstx", 4,   two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8", mfloat },
+{"ftstx", 4,   two(0xF000, 0x483A), two(0xF1C0, 0xFC7F), "Ii;x", mfloat },
+
+{"ftwotoxb", 4,        two(0xF000, 0x5811), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
+{"ftwotoxd", 4,        two(0xF000, 0x5411), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
+{"ftwotoxl", 4,        two(0xF000, 0x4011), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
+{"ftwotoxp", 4,        two(0xF000, 0x4C11), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
+{"ftwotoxs", 4,        two(0xF000, 0x4411), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
+{"ftwotoxw", 4,        two(0xF000, 0x5011), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
+{"ftwotoxx", 4,        two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
+{"ftwotoxx", 4,        two(0xF000, 0x4811), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
+{"ftwotoxx", 4,        two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiFt",   mfloat },
+
+{"halt", 2,    one(0045310),   one(0177777), "",     m68060 | mcfisa_a },
+
+{"illegal", 2, one(0045374),   one(0177777), "",     m68000up | mcfisa_a },
+{"intouch", 2, one(0xf428),    one(0xfff8), "As",    mcfisa_b },
+
+{"jmp", 2,     one(0047300),   one(0177700), "!s", m68000up | mcfisa_a },
+
+{"jra", 2,     one(0060000),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jra", 2,     one(0047300),   one(0177700), "!s", m68000up | mcfisa_a },
+
+{"jsr", 2,     one(0047200),   one(0177700), "!s", m68000up | mcfisa_a },
+
+{"jbsr", 2,    one(0060400),   one(0177400), "Bg", m68000up | mcfisa_a },
+{"jbsr", 2,    one(0047200),   one(0177700), "!s", m68000up | mcfisa_a },
+
+{"lea", 2,     one(0040700),   one(0170700), "!sAd", m68000up | mcfisa_a },
+
+{"lpstop", 6,  two(0174000,0000700),two(0177777,0177777),"#w", cpu32|m68060 },
+
+{"linkw", 4,   one(0047120),   one(0177770), "As#w", m68000up | mcfisa_a },
+{"linkl", 6,   one(0044010),   one(0177770), "As#l", m68020up | cpu32 },
+{"link", 4,    one(0047120),   one(0177770), "As#W", m68000up | mcfisa_a },
+{"link", 6,    one(0044010),   one(0177770), "As#l", m68020up | cpu32 },
+
+{"lslb", 2,    one(0160410),   one(0170770), "QdDs", m68000up },
+{"lslb", 2,    one(0160450),   one(0170770), "DdDs", m68000up },
+{"lslw", 2,    one(0160510),   one(0170770), "QdDs", m68000up },
+{"lslw", 2,    one(0160550),   one(0170770), "DdDs", m68000up },
+{"lslw", 2,    one(0161700),   one(0177700), "~s",   m68000up },
+{"lsll", 2,    one(0160610),   one(0170770), "QdDs", m68000up | mcfisa_a },
+{"lsll", 2,    one(0160650),   one(0170770), "DdDs", m68000up | mcfisa_a },
+
+{"lsrb", 2,    one(0160010),   one(0170770), "QdDs", m68000up },
+{"lsrb", 2,    one(0160050),   one(0170770), "DdDs", m68000up },
+{"lsrw", 2,    one(0160110),   one(0170770), "QdDs", m68000up },
+{"lsrw", 2,    one(0160150),   one(0170770), "DdDs", m68000up },
+{"lsrw", 2,    one(0161300),   one(0177700), "~s",   m68000up },
+{"lsrl", 2,    one(0160210),   one(0170770), "QdDs", m68000up | mcfisa_a },
+{"lsrl", 2,    one(0160250),   one(0170770), "DdDs", m68000up | mcfisa_a },
+
+{"macw", 4,    two(0xa080, 0x0000), two(0xf180, 0x0910), "uNuoiI4/Rn", mcfmac },
+{"macw", 4,    two(0xa080, 0x0200), two(0xf180, 0x0910), "uNuoMh4/Rn", mcfmac },
+{"macw", 4,    two(0xa080, 0x0000), two(0xf180, 0x0f10), "uNuo4/Rn", mcfmac },
+{"macw", 4,    two(0xa000, 0x0000), two(0xf1b0, 0x0900), "uMumiI", mcfmac },
+{"macw", 4,    two(0xa000, 0x0200), two(0xf1b0, 0x0900), "uMumMh", mcfmac },
+{"macw", 4,    two(0xa000, 0x0000), two(0xf1b0, 0x0f00), "uMum", mcfmac },
+
+{"macw", 4,    two(0xa000, 0x0000), two(0xf100, 0x0900), "uNuoiI4/RneG", mcfemac },/* Ry,Rx,SF,<ea>,accX.  */
+{"macw", 4,    two(0xa000, 0x0200), two(0xf100, 0x0900), "uNuoMh4/RneG", mcfemac },/* Ry,Rx,+1/-1,<ea>,accX.  */
+{"macw", 4,    two(0xa000, 0x0000), two(0xf100, 0x0f00), "uNuo4/RneG", mcfemac },/* Ry,Rx,<ea>,accX.  */
+{"macw", 4,    two(0xa000, 0x0000), two(0xf130, 0x0900), "uMumiIeH", mcfemac },/* Ry,Rx,SF,accX.  */
+{"macw", 4,    two(0xa000, 0x0200), two(0xf130, 0x0900), "uMumMheH", mcfemac },/* Ry,Rx,+1/-1,accX.  */
+{"macw", 4,    two(0xa000, 0x0000), two(0xf130, 0x0f00), "uMumeH", mcfemac }, /* Ry,Rx,accX.  */
+
+{"macl", 4,    two(0xa080, 0x0800), two(0xf180, 0x0910), "RNRoiI4/Rn", mcfmac },
+{"macl", 4,    two(0xa080, 0x0a00), two(0xf180, 0x0910), "RNRoMh4/Rn", mcfmac },
+{"macl", 4,    two(0xa080, 0x0800), two(0xf180, 0x0f10), "RNRo4/Rn", mcfmac },
+{"macl", 4,    two(0xa000, 0x0800), two(0xf1b0, 0x0b00), "RMRmiI", mcfmac },
+{"macl", 4,    two(0xa000, 0x0a00), two(0xf1b0, 0x0b00), "RMRmMh", mcfmac },
+{"macl", 4,    two(0xa000, 0x0800), two(0xf1b0, 0x0800), "RMRm", mcfmac },
+
+{"macl", 4,    two(0xa000, 0x0800), two(0xf100, 0x0900), "R3R1iI4/RneG", mcfemac },
+{"macl", 4,    two(0xa000, 0x0a00), two(0xf100, 0x0900), "R3R1Mh4/RneG", mcfemac },
+{"macl", 4,    two(0xa000, 0x0800), two(0xf100, 0x0f00), "R3R14/RneG", mcfemac },
+{"macl", 4,    two(0xa000, 0x0800), two(0xf130, 0x0900), "RMRmiIeH", mcfemac },
+{"macl", 4,    two(0xa000, 0x0a00), two(0xf130, 0x0900), "RMRmMheH", mcfemac },
+{"macl", 4,    two(0xa000, 0x0800), two(0xf130, 0x0f00), "RMRmeH", mcfemac },
+
+/* NOTE: The mcf5200 family programmer's reference manual does not
+   indicate the byte form of the movea instruction is invalid (as it
+   is on 68000 family cpus).  However, experiments on the 5202 yeild
+   unexpected results.  The value is copied, but it is not sign extended
+   (as is done with movea.w) and the top three bytes in the address
+   register are not disturbed.  I don't know if this is the intended
+   behavior --- it could be a hole in instruction decoding (Motorola
+   decided not to trap all invalid instructions for performance reasons)
+   --- but I suspect that it is not.
+
+   I reported this to Motorola ISD Technical Communications Support,
+   which replied that other coldfire assemblers reject movea.b.  For
+   this reason I've decided to not allow moveab.
+
+       jtc@cygnus.com - 97/01/24.  */
+
+{"moveal", 2,  one(0020100),   one(0170700), "*lAd", m68000up | mcfisa_a },
+{"moveaw", 2,  one(0030100),   one(0170700), "*wAd", m68000up | mcfisa_a },
+
+{"movclrl", 2, one(0xA1C0),    one(0xf9f0), "eFRs", mcfemac },
+
+{"movec", 4,   one(0047173),   one(0177777), "R1Jj", m68010up | mcfisa_a },
+{"movec", 4,   one(0047173),   one(0177777), "R1#j", m68010up | mcfisa_a },
+{"movec", 4,   one(0047172),   one(0177777), "JjR1", m68010up },
+{"movec", 4,   one(0047172),   one(0177777), "#jR1", m68010up },
+
+{"movemw", 4,  one(0044200),   one(0177700), "Lw&s", m68000up },
+{"movemw", 4,  one(0044240),   one(0177770), "lw-s", m68000up },
+{"movemw", 4,  one(0044200),   one(0177700), "#w>s", m68000up },
+{"movemw", 4,  one(0046200),   one(0177700), "<sLw", m68000up },
+{"movemw", 4,  one(0046200),   one(0177700), "<s#w", m68000up },
+{"moveml", 4,  one(0044300),   one(0177700), "Lw&s", m68000up },
+{"moveml", 4,  one(0044340),   one(0177770), "lw-s", m68000up },
+{"moveml", 4,  one(0044300),   one(0177700), "#w>s", m68000up },
+{"moveml", 4,  one(0046300),   one(0177700), "<sLw", m68000up },
+{"moveml", 4,  one(0046300),   one(0177700), "<s#w", m68000up },
+/* FIXME: need specifier for mode 2 and 5 to simplify below insn patterns.  */
+{"moveml", 4,  one(0044320),   one(0177770), "Lwas", mcfisa_a },
+{"moveml", 4,  one(0044320),   one(0177770), "#was", mcfisa_a },
+{"moveml", 4,  one(0044350),   one(0177770), "Lwds", mcfisa_a },
+{"moveml", 4,  one(0044350),   one(0177770), "#wds", mcfisa_a },
+{"moveml", 4,  one(0046320),   one(0177770), "asLw", mcfisa_a },
+{"moveml", 4,  one(0046320),   one(0177770), "as#w", mcfisa_a },
+{"moveml", 4,  one(0046350),   one(0177770), "dsLw", mcfisa_a },
+{"moveml", 4,  one(0046350),   one(0177770), "ds#w", mcfisa_a },
+
+{"movepw", 2,  one(0000410),   one(0170770), "dsDd", m68000up },
+{"movepw", 2,  one(0000610),   one(0170770), "Ddds", m68000up },
+{"movepl", 2,  one(0000510),   one(0170770), "dsDd", m68000up },
+{"movepl", 2,  one(0000710),   one(0170770), "Ddds", m68000up },
+
+{"moveq", 2,   one(0070000),   one(0170400), "MsDd", m68000up | mcfisa_a },
+{"moveq", 2,   one(0070000),   one(0170400), "#BDd", m68000up | mcfisa_a },
+
+/* The move opcode can generate the movea and moveq instructions.  */
+{"moveb", 2,   one(0010000),   one(0170000), ";b$d", m68000up },
+{"moveb", 2,   one(0010000),   one(0170070), "Ds$d", mcfisa_a },
+{"moveb", 2,   one(0010020),   one(0170070), "as$d", mcfisa_a },
+{"moveb", 2,   one(0010030),   one(0170070), "+s$d", mcfisa_a },
+{"moveb", 2,   one(0010040),   one(0170070), "-s$d", mcfisa_a },
+{"moveb", 2,   one(0010000),   one(0170000), "nsqd", mcfisa_a },
+{"moveb", 2,   one(0010000),   one(0170700), "obDd", mcfisa_a },
+{"moveb", 2,   one(0010200),   one(0170700), "obad", mcfisa_a },
+{"moveb", 2,   one(0010300),   one(0170700), "ob+d", mcfisa_a },
+{"moveb", 2,   one(0010400),   one(0170700), "ob-d", mcfisa_a },
+{"moveb", 2,   one(0010000),   one(0170000), "obnd", mcfisa_b },
+
+{"movew", 2,   one(0030000),   one(0170000), "*w%d", m68000up },
+{"movew", 2,   one(0030000),   one(0170000), "ms%d", mcfisa_a },
+{"movew", 2,   one(0030000),   one(0170000), "nspd", mcfisa_a },
+{"movew", 2,   one(0030000),   one(0170000), "owmd", mcfisa_a },
+{"movew", 2,   one(0030000),   one(0170000), "ownd", mcfisa_b },
+{"movew", 2,   one(0040300),   one(0177700), "Ss$s", m68000up },
+{"movew", 2,   one(0040300),   one(0177770), "SsDs", mcfisa_a },
+{"movew", 2,   one(0041300),   one(0177700), "Cs$s", m68010up },
+{"movew", 2,   one(0041300),   one(0177770), "CsDs", mcfisa_a },
+{"movew", 2,   one(0042300),   one(0177700), ";wCd", m68000up },
+{"movew", 2,   one(0042300),   one(0177700), "DsCd", mcfisa_a },
+{"movew", 4,   one(0042374),   one(0177777), "#wCd", mcfisa_a },
+{"movew", 2,   one(0043300),   one(0177700), ";wSd", m68000up },
+{"movew", 2,   one(0043300),   one(0177700), "DsSd", mcfisa_a },
+{"movew", 4,   one(0043374),   one(0177777), "#wSd", mcfisa_a },
+
+{"movel", 2,   one(0070000),   one(0170400), "MsDd", m68000up | mcfisa_a },
+{"movel", 2,   one(0020000),   one(0170000), "*l%d", m68000up },
+{"movel", 2,   one(0020000),   one(0170000), "ms%d", mcfisa_a },
+{"movel", 2,   one(0020000),   one(0170000), "nspd", mcfisa_a },
+{"movel", 2,   one(0020000),   one(0170000), "olmd", mcfisa_a },
+{"movel", 2,   one(0020000),   one(0170000), "olnd", mcfisa_b },
+{"movel", 2,   one(0047140),   one(0177770), "AsUd", m68000up | mcfusp },
+{"movel", 2,   one(0047150),   one(0177770), "UdAs", m68000up | mcfusp },
+{"movel", 2,   one(0120600),   one(0177760), "EsRs", mcfmac },
+{"movel", 2,   one(0120400),   one(0177760), "RsEs", mcfmac },
+{"movel", 6,   one(0120474),   one(0177777), "#lEs", mcfmac },
+{"movel", 2,   one(0124600),   one(0177760), "GsRs", mcfmac },
+{"movel", 2,   one(0124400),   one(0177760), "RsGs", mcfmac },
+{"movel", 6,   one(0124474),   one(0177777), "#lGs", mcfmac },
+{"movel", 2,   one(0126600),   one(0177760), "HsRs", mcfmac },
+{"movel", 2,   one(0126400),   one(0177760), "RsHs", mcfmac },
+{"movel", 6,   one(0126474),   one(0177777), "#lHs", mcfmac },
+{"movel", 2,   one(0124700),   one(0177777), "GsCs", mcfmac },
+
+{"movel", 2,   one(0xa180),    one(0xf9f0), "eFRs", mcfemac }, /* ACCx,Rx.  */
+{"movel", 2,   one(0xab80),    one(0xfbf0), "g]Rs", mcfemac }, /* ACCEXTx,Rx.  */
+{"movel", 2,   one(0xa980),    one(0xfff0), "G-Rs", mcfemac }, /* macsr,Rx.  */
+{"movel", 2,   one(0xad80),    one(0xfff0), "H-Rs", mcfemac }, /* mask,Rx.  */
+{"movel", 2,   one(0xa110),    one(0xf9fc), "efeF", mcfemac }, /* ACCy,ACCx.  */
+{"movel", 2,   one(0xa9c0),    one(0xffff), "G-C-", mcfemac }, /* macsr,ccr.  */
+{"movel", 2,   one(0xa100),    one(0xf9f0), "RseF", mcfemac }, /* Rx,ACCx.  */
+{"movel", 6,   one(0xa13c),    one(0xf9ff), "#leF", mcfemac }, /* #,ACCx.  */
+{"movel", 2,   one(0xab00),    one(0xfbc0), "Rsg]", mcfemac }, /* Rx,ACCEXTx.  */
+{"movel", 6,   one(0xab3c),    one(0xfbff), "#lg]", mcfemac }, /* #,ACCEXTx.  */
+{"movel", 2,   one(0xa900),    one(0xffc0), "RsG-", mcfemac }, /* Rx,macsr.  */
+{"movel", 6,   one(0xa93c),    one(0xffff), "#lG-", mcfemac }, /* #,macsr.  */
+{"movel", 2,   one(0xad00),    one(0xffc0), "RsH-", mcfemac }, /* Rx,mask.  */
+{"movel", 6,   one(0xad3c),    one(0xffff), "#lH-", mcfemac }, /* #,mask.  */
+
+{"move", 2,    one(0030000),   one(0170000), "*w%d", m68000up },
+{"move", 2,    one(0030000),   one(0170000), "ms%d", mcfisa_a },
+{"move", 2,    one(0030000),   one(0170000), "nspd", mcfisa_a },
+{"move", 2,    one(0030000),   one(0170000), "owmd", mcfisa_a },
+{"move", 2,    one(0030000),   one(0170000), "ownd", mcfisa_b },
+{"move", 2,    one(0040300),   one(0177700), "Ss$s", m68000up },
+{"move", 2,    one(0040300),   one(0177770), "SsDs", mcfisa_a },
+{"move", 2,    one(0041300),   one(0177700), "Cs$s", m68010up },
+{"move", 2,    one(0041300),   one(0177770), "CsDs", mcfisa_a },
+{"move", 2,    one(0042300),   one(0177700), ";wCd", m68000up },
+{"move", 2,    one(0042300),   one(0177700), "DsCd", mcfisa_a },
+{"move", 4,    one(0042374),   one(0177777), "#wCd", mcfisa_a },
+{"move", 2,    one(0043300),   one(0177700), ";wSd", m68000up },
+{"move", 2,    one(0043300),   one(0177700), "DsSd", mcfisa_a },
+{"move", 4,    one(0043374),   one(0177777), "#wSd", mcfisa_a },
+
+{"move", 2,    one(0047140),   one(0177770), "AsUd", m68000up },
+{"move", 2,    one(0047150),   one(0177770), "UdAs", m68000up },
+
+{"mov3ql", 2,  one(0120500),   one(0170700), "xd%s", mcfisa_b },
+{"mvsb", 2,    one(0070400),   one(0170700), "*bDd", mcfisa_b },
+{"mvsw", 2,    one(0070500),   one(0170700), "*wDd", mcfisa_b },
+{"mvzb", 2,    one(0070600),   one(0170700), "*bDd", mcfisa_b },
+{"mvzw", 2,    one(0070700),   one(0170700), "*wDd", mcfisa_b },
+
+{"movesb", 4,  two(0007000, 0),     two(0177700, 07777), "~sR1", m68010up },
+{"movesb", 4,  two(0007000, 04000), two(0177700, 07777), "R1~s", m68010up },
+{"movesw", 4,  two(0007100, 0),     two(0177700, 07777), "~sR1", m68010up },
+{"movesw", 4,  two(0007100, 04000), two(0177700, 07777), "R1~s", m68010up },
+{"movesl", 4,  two(0007200, 0),     two(0177700, 07777), "~sR1", m68010up },
+{"movesl", 4,  two(0007200, 04000), two(0177700, 07777), "R1~s", m68010up },
+
+{"move16", 4,  two(0xf620, 0x8000), two(0xfff8, 0x8fff), "+s+1", m68040up },
+{"move16", 2,  one(0xf600),            one(0xfff8), "+s_L", m68040up },
+{"move16", 2,  one(0xf608),            one(0xfff8), "_L+s", m68040up },
+{"move16", 2,  one(0xf610),            one(0xfff8), "as_L", m68040up },
+{"move16", 2,  one(0xf618),            one(0xfff8), "_Las", m68040up },
+
+{"msacw", 4,   two(0xa080, 0x0100), two(0xf180, 0x0910), "uNuoiI4/Rn", mcfmac },
+{"msacw", 4,   two(0xa080, 0x0300), two(0xf180, 0x0910), "uNuoMh4/Rn", mcfmac },
+{"msacw", 4,   two(0xa080, 0x0100), two(0xf180, 0x0f10), "uNuo4/Rn", mcfmac },
+{"msacw", 4,   two(0xa000, 0x0100), two(0xf1b0, 0x0900), "uMumiI", mcfmac },
+{"msacw", 4,   two(0xa000, 0x0300), two(0xf1b0, 0x0900), "uMumMh", mcfmac },
+{"msacw", 4,   two(0xa000, 0x0100), two(0xf1b0, 0x0f00), "uMum", mcfmac },
+
+{"msacw", 4,   two(0xa000, 0x0100), two(0xf100, 0x0900), "uMumiI4/RneG", mcfemac },/* Ry,Rx,SF,<ea>,accX.  */
+{"msacw", 4,   two(0xa000, 0x0300), two(0xf100, 0x0900), "uMumMh4/RneG", mcfemac },/* Ry,Rx,+1/-1,<ea>,accX.  */
+{"msacw", 4,   two(0xa000, 0x0100), two(0xf100, 0x0f00), "uMum4/RneG", mcfemac },/* Ry,Rx,<ea>,accX.  */
+{"msacw", 4,   two(0xa000, 0x0100), two(0xf130, 0x0900), "uMumiIeH", mcfemac },/* Ry,Rx,SF,accX.  */
+{"msacw", 4,   two(0xa000, 0x0300), two(0xf130, 0x0900), "uMumMheH", mcfemac },/* Ry,Rx,+1/-1,accX.  */
+{"msacw", 4,   two(0xa000, 0x0100), two(0xf130, 0x0f00), "uMumeH", mcfemac }, /* Ry,Rx,accX.  */
+
+{"msacl", 4,   two(0xa080, 0x0900), two(0xf180, 0x0910), "RNRoiI4/Rn", mcfmac },
+{"msacl", 4,   two(0xa080, 0x0b00), two(0xf180, 0x0910), "RNRoMh4/Rn", mcfmac },
+{"msacl", 4,   two(0xa080, 0x0900), two(0xf180, 0x0f10), "RNRo4/Rn", mcfmac },
+{"msacl", 4,   two(0xa000, 0x0900), two(0xf1b0, 0x0b00), "RMRmiI", mcfmac },
+{"msacl", 4,   two(0xa000, 0x0b00), two(0xf1b0, 0x0b00), "RMRmMh", mcfmac },
+{"msacl", 4,   two(0xa000, 0x0900), two(0xf1b0, 0x0800), "RMRm", mcfmac },
+
+{"msacl", 4,   two(0xa000, 0x0900), two(0xf100, 0x0900), "R3R1iI4/RneG", mcfemac },
+{"msacl", 4,   two(0xa000, 0x0b00), two(0xf100, 0x0900), "R3R1Mh4/RneG", mcfemac },
+{"msacl", 4,   two(0xa000, 0x0900), two(0xf100, 0x0f00), "R3R14/RneG", mcfemac },
+{"msacl", 4,   two(0xa000, 0x0900), two(0xf130, 0x0900), "RMRmiIeH", mcfemac },
+{"msacl", 4,   two(0xa000, 0x0b00), two(0xf130, 0x0900), "RMRmMheH", mcfemac },
+{"msacl", 4,   two(0xa000, 0x0900), two(0xf130, 0x0f00), "RMRmeH", mcfemac },
+
+{"mulsw", 2,   one(0140700),           one(0170700), ";wDd", m68000up|mcfisa_a },
+{"mulsl", 4,   two(0046000,004000), two(0177700,0107770), ";lD1", m68020up|cpu32 },
+{"mulsl", 4,   two(0046000,004000), two(0177700,0107770), "qsD1", mcfisa_a },
+{"mulsl", 4,   two(0046000,006000), two(0177700,0107770), ";lD3D1",m68020up|cpu32 },
+
+{"muluw", 2,   one(0140300),           one(0170700), ";wDd", m68000up|mcfisa_a },
+{"mulul", 4,   two(0046000,000000), two(0177700,0107770), ";lD1", m68020up|cpu32 },
+{"mulul", 4,   two(0046000,000000), two(0177700,0107770), "qsD1", mcfisa_a },
+{"mulul", 4,   two(0046000,002000), two(0177700,0107770), ";lD3D1",m68020up|cpu32 },
+
+{"nbcd", 2,    one(0044000),   one(0177700), "$s", m68000up },
+
+{"negb", 2,    one(0042000),   one(0177700), "$s", m68000up },
+{"negw", 2,    one(0042100),   one(0177700), "$s", m68000up },
+{"negl", 2,    one(0042200),   one(0177700), "$s", m68000up },
+{"negl", 2,    one(0042200),   one(0177700), "Ds", mcfisa_a},
+
+{"negxb", 2,   one(0040000),   one(0177700), "$s", m68000up },
+{"negxw", 2,   one(0040100),   one(0177700), "$s", m68000up },
+{"negxl", 2,   one(0040200),   one(0177700), "$s", m68000up },
+{"negxl", 2,   one(0040200),   one(0177700), "Ds", mcfisa_a},
+
+{"nop", 2,     one(0047161),   one(0177777), "", m68000up | mcfisa_a},
+
+{"notb", 2,    one(0043000),   one(0177700), "$s", m68000up },
+{"notw", 2,    one(0043100),   one(0177700), "$s", m68000up },
+{"notl", 2,    one(0043200),   one(0177700), "$s", m68000up },
+{"notl", 2,    one(0043200),   one(0177700), "Ds", mcfisa_a},
+
+{"orib", 4,    one(0000000),   one(0177700), "#b$s", m68000up },
+{"orib", 4,    one(0000074),   one(0177777), "#bCs", m68000up },
+{"oriw", 4,    one(0000100),   one(0177700), "#w$s", m68000up },
+{"oriw", 4,    one(0000174),   one(0177777), "#wSs", m68000up },
+{"oril", 6,    one(0000200),   one(0177700), "#l$s", m68000up },
+{"oril", 6,    one(0000200),   one(0177700), "#lDs", mcfisa_a },
+{"ori", 4,     one(0000074),   one(0177777), "#bCs", m68000up },
+{"ori", 4,     one(0000100),   one(0177700), "#w$s", m68000up },
+{"ori", 4,     one(0000174),   one(0177777), "#wSs", m68000up },
+
+/* The or opcode can generate the ori instruction.  */
+{"orb", 4,     one(0000000),   one(0177700), "#b$s", m68000up },
+{"orb", 4,     one(0000074),   one(0177777), "#bCs", m68000up },
+{"orb", 2,     one(0100000),   one(0170700), ";bDd", m68000up },
+{"orb", 2,     one(0100400),   one(0170700), "Dd~s", m68000up },
+{"orw", 4,     one(0000100),   one(0177700), "#w$s", m68000up },
+{"orw", 4,     one(0000174),   one(0177777), "#wSs", m68000up },
+{"orw", 2,     one(0100100),   one(0170700), ";wDd", m68000up },
+{"orw", 2,     one(0100500),   one(0170700), "Dd~s", m68000up },
+{"orl", 6,     one(0000200),   one(0177700), "#l$s", m68000up },
+{"orl", 6,     one(0000200),   one(0177700), "#lDs", mcfisa_a },
+{"orl", 2,     one(0100200),   one(0170700), ";lDd", m68000up | mcfisa_a },
+{"orl", 2,     one(0100600),   one(0170700), "Dd~s", m68000up | mcfisa_a },
+{"or", 4,      one(0000074),   one(0177777), "#bCs", m68000up },
+{"or", 4,      one(0000100),   one(0177700), "#w$s", m68000up },
+{"or", 4,      one(0000174),   one(0177777), "#wSs", m68000up },
+{"or", 2,      one(0100100),   one(0170700), ";wDd", m68000up },
+{"or", 2,      one(0100500),   one(0170700), "Dd~s", m68000up },
+
+{"pack", 4,    one(0100500),   one(0170770), "DsDd#w", m68020up },
+{"pack", 4,    one(0100510),   one(0170770), "-s-d#w", m68020up },
+
+{"pbac", 2,    one(0xf087),    one(0xffbf), "Bc", m68851 },
+{"pbacw", 2,   one(0xf087),    one(0xffff), "BW", m68851 },
+{"pbas", 2,    one(0xf086),    one(0xffbf), "Bc", m68851 },
+{"pbasw", 2,   one(0xf086),    one(0xffff), "BW", m68851 },
+{"pbbc", 2,    one(0xf081),    one(0xffbf), "Bc", m68851 },
+{"pbbcw", 2,   one(0xf081),    one(0xffff), "BW", m68851 },
+{"pbbs", 2,    one(0xf080),    one(0xffbf), "Bc", m68851 },
+{"pbbsw", 2,   one(0xf080),    one(0xffff), "BW", m68851 },
+{"pbcc", 2,    one(0xf08f),    one(0xffbf), "Bc", m68851 },
+{"pbccw", 2,   one(0xf08f),    one(0xffff), "BW", m68851 },
+{"pbcs", 2,    one(0xf08e),    one(0xffbf), "Bc", m68851 },
+{"pbcsw", 2,   one(0xf08e),    one(0xffff), "BW", m68851 },
+{"pbgc", 2,    one(0xf08d),    one(0xffbf), "Bc", m68851 },
+{"pbgcw", 2,   one(0xf08d),    one(0xffff), "BW", m68851 },
+{"pbgs", 2,    one(0xf08c),    one(0xffbf), "Bc", m68851 },
+{"pbgsw", 2,   one(0xf08c),    one(0xffff), "BW", m68851 },
+{"pbic", 2,    one(0xf08b),    one(0xffbf), "Bc", m68851 },
+{"pbicw", 2,   one(0xf08b),    one(0xffff), "BW", m68851 },
+{"pbis", 2,    one(0xf08a),    one(0xffbf), "Bc", m68851 },
+{"pbisw", 2,   one(0xf08a),    one(0xffff), "BW", m68851 },
+{"pblc", 2,    one(0xf083),    one(0xffbf), "Bc", m68851 },
+{"pblcw", 2,   one(0xf083),    one(0xffff), "BW", m68851 },
+{"pbls", 2,    one(0xf082),    one(0xffbf), "Bc", m68851 },
+{"pblsw", 2,   one(0xf082),    one(0xffff), "BW", m68851 },
+{"pbsc", 2,    one(0xf085),    one(0xffbf), "Bc", m68851 },
+{"pbscw", 2,   one(0xf085),    one(0xffff), "BW", m68851 },
+{"pbss", 2,    one(0xf084),    one(0xffbf), "Bc", m68851 },
+{"pbssw", 2,   one(0xf084),    one(0xffff), "BW", m68851 },
+{"pbwc", 2,    one(0xf089),    one(0xffbf), "Bc", m68851 },
+{"pbwcw", 2,   one(0xf089),    one(0xffff), "BW", m68851 },
+{"pbws", 2,    one(0xf088),    one(0xffbf), "Bc", m68851 },
+{"pbwsw", 2,   one(0xf088),    one(0xffff), "BW", m68851 },
+
+{"pdbac", 4,   two(0xf048, 0x0007),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbas", 4,   two(0xf048, 0x0006),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbbc", 4,   two(0xf048, 0x0001),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbbs", 4,   two(0xf048, 0x0000),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbcc", 4,   two(0xf048, 0x000f),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbcs", 4,   two(0xf048, 0x000e),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbgc", 4,   two(0xf048, 0x000d),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbgs", 4,   two(0xf048, 0x000c),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbic", 4,   two(0xf048, 0x000b),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbis", 4,   two(0xf048, 0x000a),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdblc", 4,   two(0xf048, 0x0003),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbls", 4,   two(0xf048, 0x0002),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbsc", 4,   two(0xf048, 0x0005),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbss", 4,   two(0xf048, 0x0004),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbwc", 4,   two(0xf048, 0x0009),    two(0xfff8, 0xffff), "DsBw", m68851 },
+{"pdbws", 4,   two(0xf048, 0x0008),    two(0xfff8, 0xffff), "DsBw", m68851 },
+
+{"pea", 2,     one(0044100),           one(0177700), "!s", m68000up|mcfisa_a },
+
+{"pflusha", 2, one(0xf518),            one(0xfff8), "", m68040up },
+{"pflusha", 4, two(0xf000,0x2400), two(0xffff,0xffff), "", m68030 | m68851 },
+
+{"pflush", 4,   two(0xf000,0x3010), two(0xffc0,0xfe10), "T3T9", m68030|m68851 },
+{"pflush", 4,   two(0xf000,0x3810), two(0xffc0,0xfe10), "T3T9&s", m68030|m68851 },
+{"pflush", 4,   two(0xf000,0x3008), two(0xffc0,0xfe18), "D3T9", m68030|m68851 },
+{"pflush", 4,   two(0xf000,0x3808), two(0xffc0,0xfe18), "D3T9&s", m68030|m68851 },
+{"pflush", 4,   two(0xf000,0x3000), two(0xffc0,0xfe1e), "f3T9", m68030|m68851 },
+{"pflush", 4,   two(0xf000,0x3800), two(0xffc0,0xfe1e), "f3T9&s", m68030|m68851 },
+{"pflush", 2,  one(0xf508),            one(0xfff8), "as", m68040up },
+{"pflush", 2,  one(0xf508),            one(0xfff8), "As", m68040up },
+
+{"pflushan", 2,        one(0xf510),            one(0xfff8), "", m68040up },
+{"pflushn", 2, one(0xf500),            one(0xfff8), "as", m68040up },
+{"pflushn", 2, one(0xf500),            one(0xfff8), "As", m68040up },
+
+{"pflushr", 4, two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s", m68851 },
+
+{"pflushs", 4, two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9", m68851 },
+{"pflushs", 4, two(0xf000, 0x3c10), two(0xfff8, 0xfe10), "T3T9&s", m68851 },
+{"pflushs", 4, two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9", m68851 },
+{"pflushs", 4, two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s", m68851 },
+{"pflushs", 4, two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9", m68851 },
+{"pflushs", 4, two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s", m68851 },
+
+{"ploadr", 4,   two(0xf000,0x2210), two(0xffc0,0xfff0), "T3&s", m68030|m68851 },
+{"ploadr", 4,   two(0xf000,0x2208), two(0xffc0,0xfff8), "D3&s", m68030|m68851 },
+{"ploadr", 4,   two(0xf000,0x2200), two(0xffc0,0xfffe), "f3&s", m68030|m68851 },
+{"ploadw", 4,   two(0xf000,0x2010), two(0xffc0,0xfff0), "T3&s", m68030|m68851 },
+{"ploadw", 4,   two(0xf000,0x2008), two(0xffc0,0xfff8), "D3&s", m68030|m68851 },
+{"ploadw", 4,   two(0xf000,0x2000), two(0xffc0,0xfffe), "f3&s", m68030|m68851 },
+
+{"plpar", 2,   one(0xf5c8),            one(0xfff8), "as", m68060 },
+{"plpaw", 2,   one(0xf588),            one(0xfff8), "as", m68060 },
+
+{"pmove", 4,    two(0xf000,0x4000), two(0xffc0,0xffff), "*l08", m68030|m68851 },
+{"pmove", 4,    two(0xf000,0x5c00), two(0xffc0,0xffff), "*w18", m68851 },
+{"pmove", 4,    two(0xf000,0x4000), two(0xffc0,0xe3ff), "*b28", m68851 },
+{"pmove", 4,    two(0xf000,0x4200), two(0xffc0,0xffff), "08%s", m68030|m68851 },
+{"pmove", 4,    two(0xf000,0x5e00), two(0xffc0,0xffff), "18%s", m68851 },
+{"pmove", 4,    two(0xf000,0x4200), two(0xffc0,0xe3ff), "28%s", m68851 },
+{"pmove", 4,    two(0xf000,0x4000), two(0xffc0,0xe3ff), "|sW8", m68030|m68851 },
+{"pmove", 4,    two(0xf000,0x4200), two(0xffc0,0xe3ff), "W8~s", m68030|m68851 },
+{"pmove", 4,    two(0xf000,0x6200), two(0xffc0,0xe3e3), "*wX3", m68851 },
+{"pmove", 4,    two(0xf000,0x6000), two(0xffc0,0xe3e3), "X3%s", m68851 },
+{"pmove", 4,    two(0xf000,0x6000), two(0xffc0,0xffff), "*wY8", m68030|m68851 },
+{"pmove", 4,    two(0xf000,0x6200), two(0xffc0,0xffff), "Y8%s", m68030|m68851 },
+{"pmove", 4,    two(0xf000,0x6600), two(0xffc0,0xffff), "Z8%s", m68851 },
+{"pmove", 4,    two(0xf000,0x0800), two(0xffc0,0xfbff), "*l38", m68030 },
+{"pmove", 4,    two(0xf000,0x0a00), two(0xffc0,0xfbff), "38%s", m68030 },
+
+{"pmovefd", 4, two(0xf000, 0x4100),    two(0xffc0, 0xe3ff), "*l08", m68030 },
+{"pmovefd", 4, two(0xf000, 0x4100),    two(0xffc0, 0xe3ff), "|sW8", m68030 },
+{"pmovefd", 4, two(0xf000, 0x0900),    two(0xffc0, 0xfbff), "*l38", m68030 },
+
+{"prestore", 2,        one(0xf140),            one(0xffc0), "<s", m68851 },
+
+{"psave", 2,   one(0xf100),            one(0xffc0), ">s", m68851 },
+
+{"psac", 4,    two(0xf040, 0x0007),    two(0xffc0, 0xffff), "$s", m68851 },
+{"psas", 4,    two(0xf040, 0x0006),    two(0xffc0, 0xffff), "$s", m68851 },
+{"psbc", 4,    two(0xf040, 0x0001),    two(0xffc0, 0xffff), "$s", m68851 },
+{"psbs", 4,    two(0xf040, 0x0000),    two(0xffc0, 0xffff), "$s", m68851 },
+{"pscc", 4,    two(0xf040, 0x000f),    two(0xffc0, 0xffff), "$s", m68851 },
+{"pscs", 4,    two(0xf040, 0x000e),    two(0xffc0, 0xffff), "$s", m68851 },
+{"psgc", 4,    two(0xf040, 0x000d),    two(0xffc0, 0xffff), "$s", m68851 },
+{"psgs", 4,    two(0xf040, 0x000c),    two(0xffc0, 0xffff), "$s", m68851 },
+{"psic", 4,    two(0xf040, 0x000b),    two(0xffc0, 0xffff), "$s", m68851 },
+{"psis", 4,    two(0xf040, 0x000a),    two(0xffc0, 0xffff), "$s", m68851 },
+{"pslc", 4,    two(0xf040, 0x0003),    two(0xffc0, 0xffff), "$s", m68851 },
+{"psls", 4,    two(0xf040, 0x0002),    two(0xffc0, 0xffff), "$s", m68851 },
+{"pssc", 4,    two(0xf040, 0x0005),    two(0xffc0, 0xffff), "$s", m68851 },
+{"psss", 4,    two(0xf040, 0x0004),    two(0xffc0, 0xffff), "$s", m68851 },
+{"pswc", 4,    two(0xf040, 0x0009),    two(0xffc0, 0xffff), "$s", m68851 },
+{"psws", 4,    two(0xf040, 0x0008),    two(0xffc0, 0xffff), "$s", m68851 },
+
+{"ptestr", 4,  two(0xf000,0x8210), two(0xffc0, 0xe3f0), "T3&st8", m68030|m68851 },
+{"ptestr", 4,  two(0xf000,0x8310), two(0xffc0,0xe310), "T3&st8A9", m68030|m68851 },
+{"ptestr", 4,  two(0xf000,0x8208), two(0xffc0,0xe3f8), "D3&st8", m68030|m68851 },
+{"ptestr", 4,  two(0xf000,0x8308), two(0xffc0,0xe318), "D3&st8A9", m68030|m68851 },
+{"ptestr", 4,  two(0xf000,0x8200), two(0xffc0,0xe3fe), "f3&st8", m68030|m68851 },
+{"ptestr", 4,  two(0xf000,0x8300), two(0xffc0,0xe31e), "f3&st8A9", m68030|m68851 },
+{"ptestr", 2,  one(0xf568),            one(0xfff8), "as", m68040 },
+
+{"ptestw", 4,  two(0xf000,0x8010), two(0xffc0,0xe3f0), "T3&st8", m68030|m68851 },
+{"ptestw", 4,  two(0xf000,0x8110), two(0xffc0,0xe310), "T3&st8A9", m68030|m68851 },
+{"ptestw", 4,  two(0xf000,0x8008), two(0xffc0,0xe3f8), "D3&st8", m68030|m68851 },
+{"ptestw", 4,  two(0xf000,0x8108), two(0xffc0,0xe318), "D3&st8A9", m68030|m68851 },
+{"ptestw", 4,  two(0xf000,0x8000), two(0xffc0,0xe3fe), "f3&st8", m68030|m68851 },
+{"ptestw", 4,  two(0xf000,0x8100), two(0xffc0,0xe31e), "f3&st8A9", m68030|m68851 },
+{"ptestw", 2,  one(0xf548),            one(0xfff8), "as", m68040 },
+
+{"ptrapacw", 6,        two(0xf07a, 0x0007),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapacl", 6,        two(0xf07b, 0x0007),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapac", 4, two(0xf07c, 0x0007),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapasw", 6,        two(0xf07a, 0x0006),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapasl", 6,        two(0xf07b, 0x0006),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapas", 4, two(0xf07c, 0x0006),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapbcw", 6,        two(0xf07a, 0x0001),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapbcl", 6,        two(0xf07b, 0x0001),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapbc", 4, two(0xf07c, 0x0001),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapbsw", 6,        two(0xf07a, 0x0000),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapbsl", 6,        two(0xf07b, 0x0000),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapbs", 4, two(0xf07c, 0x0000),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapccw", 6,        two(0xf07a, 0x000f),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapccl", 6,        two(0xf07b, 0x000f),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapcc", 4, two(0xf07c, 0x000f),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapcsw", 6,        two(0xf07a, 0x000e),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapcsl", 6,        two(0xf07b, 0x000e),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapcs", 4, two(0xf07c, 0x000e),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapgcw", 6,        two(0xf07a, 0x000d),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapgcl", 6,        two(0xf07b, 0x000d),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapgc", 4, two(0xf07c, 0x000d),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapgsw", 6,        two(0xf07a, 0x000c),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapgsl", 6,        two(0xf07b, 0x000c),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapgs", 4, two(0xf07c, 0x000c),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapicw", 6,        two(0xf07a, 0x000b),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapicl", 6,        two(0xf07b, 0x000b),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapic", 4, two(0xf07c, 0x000b),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapisw", 6,        two(0xf07a, 0x000a),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapisl", 6,        two(0xf07b, 0x000a),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapis", 4, two(0xf07c, 0x000a),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptraplcw", 6,        two(0xf07a, 0x0003),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptraplcl", 6,        two(0xf07b, 0x0003),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptraplc", 4, two(0xf07c, 0x0003),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptraplsw", 6,        two(0xf07a, 0x0002),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptraplsl", 6,        two(0xf07b, 0x0002),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapls", 4, two(0xf07c, 0x0002),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapscw", 6,        two(0xf07a, 0x0005),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapscl", 6,        two(0xf07b, 0x0005),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapsc", 4, two(0xf07c, 0x0005),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapssw", 6,        two(0xf07a, 0x0004),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapssl", 6,        two(0xf07b, 0x0004),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapss", 4, two(0xf07c, 0x0004),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapwcw", 6,        two(0xf07a, 0x0009),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapwcl", 6,        two(0xf07b, 0x0009),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapwc", 4, two(0xf07c, 0x0009),    two(0xffff, 0xffff), "",   m68851 },
+
+{"ptrapwsw", 6,        two(0xf07a, 0x0008),    two(0xffff, 0xffff), "#w", m68851 },
+{"ptrapwsl", 6,        two(0xf07b, 0x0008),    two(0xffff, 0xffff), "#l", m68851 },
+{"ptrapws", 4, two(0xf07c, 0x0008),    two(0xffff, 0xffff), "",   m68851 },
+
+{"pulse", 2,   one(0045314),           one(0177777), "", m68060 | mcfisa_a },
+
+{"pvalid", 4,  two(0xf000, 0x2800),    two(0xffc0, 0xffff), "Vs&s", m68851 },
+{"pvalid", 4,  two(0xf000, 0x2c00),    two(0xffc0, 0xfff8), "A3&s", m68851 },
+
+  /* FIXME: don't allow Dw==Dx. */
+{"remsl", 4,    two(0x4c40, 0x0800),    two(0xffc0, 0x8ff8), "qsD3D1", mcfhwdiv },
+{"remul", 4,    two(0x4c40, 0x0000),    two(0xffc0, 0x8ff8), "qsD3D1", mcfhwdiv },
+
+{"reset", 2,   one(0047160),           one(0177777), "", m68000up },
+
+{"rolb", 2,    one(0160430),           one(0170770), "QdDs", m68000up },
+{"rolb", 2,    one(0160470),           one(0170770), "DdDs", m68000up },
+{"rolw", 2,    one(0160530),           one(0170770), "QdDs", m68000up },
+{"rolw", 2,    one(0160570),           one(0170770), "DdDs", m68000up },
+{"rolw", 2,    one(0163700),           one(0177700), "~s",   m68000up },
+{"roll", 2,    one(0160630),           one(0170770), "QdDs", m68000up },
+{"roll", 2,    one(0160670),           one(0170770), "DdDs", m68000up },
+
+{"rorb", 2,    one(0160030),           one(0170770), "QdDs", m68000up },
+{"rorb", 2,    one(0160070),           one(0170770), "DdDs", m68000up },
+{"rorw", 2,    one(0160130),           one(0170770), "QdDs", m68000up },
+{"rorw", 2,    one(0160170),           one(0170770), "DdDs", m68000up },
+{"rorw", 2,    one(0163300),           one(0177700), "~s",   m68000up },
+{"rorl", 2,    one(0160230),           one(0170770), "QdDs", m68000up },
+{"rorl", 2,    one(0160270),           one(0170770), "DdDs", m68000up },
+
+{"roxlb", 2,   one(0160420),           one(0170770), "QdDs", m68000up },
+{"roxlb", 2,   one(0160460),           one(0170770), "DdDs", m68000up },
+{"roxlw", 2,   one(0160520),           one(0170770), "QdDs", m68000up },
+{"roxlw", 2,   one(0160560),           one(0170770), "DdDs", m68000up },
+{"roxlw", 2,   one(0162700),           one(0177700), "~s",   m68000up },
+{"roxll", 2,   one(0160620),           one(0170770), "QdDs", m68000up },
+{"roxll", 2,   one(0160660),           one(0170770), "DdDs", m68000up },
+
+{"roxrb", 2,   one(0160020),           one(0170770), "QdDs", m68000up },
+{"roxrb", 2,   one(0160060),           one(0170770), "DdDs", m68000up },
+{"roxrw", 2,   one(0160120),           one(0170770), "QdDs", m68000up },
+{"roxrw", 2,   one(0160160),           one(0170770), "DdDs", m68000up },
+{"roxrw", 2,   one(0162300),           one(0177700), "~s",   m68000up },
+{"roxrl", 2,   one(0160220),           one(0170770), "QdDs", m68000up },
+{"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 },
+
+{"sbcd", 2,    one(0100400),           one(0170770), "DsDd", m68000up },
+{"sbcd", 2,    one(0100410),           one(0170770), "-s-d", m68000up },
+
+{"scc", 2,     one(0052300),   one(0177700), "$s", m68000up },
+{"scc", 2,     one(0052300),   one(0177700), "Ds", mcfisa_a },
+{"scs", 2,     one(0052700),   one(0177700), "$s", m68000up },
+{"scs", 2,     one(0052700),   one(0177700), "Ds", mcfisa_a },
+{"seq", 2,     one(0053700),   one(0177700), "$s", m68000up },
+{"seq", 2,     one(0053700),   one(0177700), "Ds", mcfisa_a },
+{"sf", 2,      one(0050700),   one(0177700), "$s", m68000up },
+{"sf", 2,      one(0050700),   one(0177700), "Ds", mcfisa_a },
+{"sge", 2,     one(0056300),   one(0177700), "$s", m68000up },
+{"sge", 2,     one(0056300),   one(0177700), "Ds", mcfisa_a },
+{"sgt", 2,     one(0057300),   one(0177700), "$s", m68000up },
+{"sgt", 2,     one(0057300),   one(0177700), "Ds", mcfisa_a },
+{"shi", 2,     one(0051300),   one(0177700), "$s", m68000up },
+{"shi", 2,     one(0051300),   one(0177700), "Ds", mcfisa_a },
+{"sle", 2,     one(0057700),   one(0177700), "$s", m68000up },
+{"sle", 2,     one(0057700),   one(0177700), "Ds", mcfisa_a },
+{"sls", 2,     one(0051700),   one(0177700), "$s", m68000up },
+{"sls", 2,     one(0051700),   one(0177700), "Ds", mcfisa_a },
+{"slt", 2,     one(0056700),   one(0177700), "$s", m68000up },
+{"slt", 2,     one(0056700),   one(0177700), "Ds", mcfisa_a },
+{"smi", 2,     one(0055700),   one(0177700), "$s", m68000up },
+{"smi", 2,     one(0055700),   one(0177700), "Ds", mcfisa_a },
+{"sne", 2,     one(0053300),   one(0177700), "$s", m68000up },
+{"sne", 2,     one(0053300),   one(0177700), "Ds", mcfisa_a },
+{"spl", 2,     one(0055300),   one(0177700), "$s", m68000up },
+{"spl", 2,     one(0055300),   one(0177700), "Ds", mcfisa_a },
+{"st", 2,      one(0050300),   one(0177700), "$s", m68000up },
+{"st", 2,      one(0050300),   one(0177700), "Ds", mcfisa_a },
+{"svc", 2,     one(0054300),   one(0177700), "$s", m68000up },
+{"svc", 2,     one(0054300),   one(0177700), "Ds", mcfisa_a },
+{"svs", 2,     one(0054700),   one(0177700), "$s", m68000up },
+{"svs", 2,     one(0054700),   one(0177700), "Ds", mcfisa_a },
+
+{"stop", 4,    one(0047162),   one(0177777), "#w", m68000up | mcfisa_a },
+
+{"strldsr", 4, two(0040347,0043374), two(0177777,0177777), "#w", mcfisa_aa},
+
+{"subal", 2,   one(0110700),   one(0170700), "*lAd", m68000up | mcfisa_a },
+{"subaw", 2,   one(0110300),   one(0170700), "*wAd", m68000up },
+
+{"subib", 4,   one(0002000),   one(0177700), "#b$s", m68000up },
+{"subiw", 4,   one(0002100),   one(0177700), "#w$s", m68000up },
+{"subil", 6,   one(0002200),   one(0177700), "#l$s", m68000up },
+{"subil", 6,   one(0002200),   one(0177700), "#lDs", mcfisa_a },
+
+{"subqb", 2,   one(0050400),   one(0170700), "Qd%s", m68000up },
+{"subqw", 2,   one(0050500),   one(0170700), "Qd%s", m68000up },
+{"subql", 2,   one(0050600),   one(0170700), "Qd%s", m68000up | mcfisa_a },
+
+/* The sub opcode can generate the suba, subi, and subq instructions.  */
+{"subb", 2,    one(0050400),   one(0170700), "Qd%s", m68000up },
+{"subb", 4,    one(0002000),   one(0177700), "#b$s", m68000up },
+{"subb", 2,    one(0110000),   one(0170700), ";bDd", m68000up },
+{"subb", 2,    one(0110400),   one(0170700), "Dd~s", m68000up },
+{"subw", 2,    one(0050500),   one(0170700), "Qd%s", m68000up },
+{"subw", 4,    one(0002100),   one(0177700), "#w$s", m68000up },
+{"subw", 2,    one(0110300),   one(0170700), "*wAd", m68000up },
+{"subw", 2,    one(0110100),   one(0170700), "*wDd", m68000up },
+{"subw", 2,    one(0110500),   one(0170700), "Dd~s", m68000up },
+{"subl", 2,    one(0050600),   one(0170700), "Qd%s", m68000up | mcfisa_a },
+{"subl", 6,    one(0002200),   one(0177700), "#l$s", m68000up },
+{"subl", 6,    one(0002200),   one(0177700), "#lDs", mcfisa_a },
+{"subl", 2,    one(0110700),   one(0170700), "*lAd", m68000up | mcfisa_a },
+{"subl", 2,    one(0110200),   one(0170700), "*lDd", m68000up | mcfisa_a },
+{"subl", 2,    one(0110600),   one(0170700), "Dd~s", m68000up | mcfisa_a },
+
+{"subxb", 2,   one(0110400),   one(0170770), "DsDd", m68000up },
+{"subxb", 2,   one(0110410),   one(0170770), "-s-d", m68000up },
+{"subxw", 2,   one(0110500),   one(0170770), "DsDd", m68000up },
+{"subxw", 2,   one(0110510),   one(0170770), "-s-d", m68000up },
+{"subxl", 2,   one(0110600),   one(0170770), "DsDd", m68000up | mcfisa_a },
+{"subxl", 2,   one(0110610),   one(0170770), "-s-d", m68000up },
+
+{"swap", 2,    one(0044100),   one(0177770), "Ds", m68000up | mcfisa_a },
+
+/* swbeg and swbegl are magic constants used on sysV68.  The compiler
+   generates them before a switch table.  They tell the debugger and
+   disassembler that a switch table follows.  The parameter is the
+   number of elements in the table.  swbeg means that the entries in
+   the table are word (2 byte) sized, and swbegl means that the
+   entries in the table are longword (4 byte) sized.  */
+{"swbeg", 4,   one(0045374),   one(0177777), "#w",   m68000up | mcfisa_a },
+{"swbegl", 6,  one(0045375),   one(0177777), "#l",   m68000up | mcfisa_a },
+
+{"tas", 2,     one(0045300),   one(0177700), "$s", m68000up | mcfisa_b},
+
+#define TBL1(name,insn_size,signed,round,size)                                 \
+  {name, insn_size, two(0174000, (signed<<11)|(!round<<10)|(size<<6)|0000400), \
+     two(0177700,0107777), "!sD1", cpu32 },                            \
+  {name, insn_size, two(0174000, (signed<<11)|(!round<<10)|(size<<6)),         \
+     two(0177770,0107770), "DsD3D1", cpu32 }
+#define TBL(name1, name2, name3, s, r) \
+  TBL1(name1, 4, s, r, 0), TBL1(name2, 4, s, r, 1), TBL1(name3, 4, s, r, 2)
+TBL("tblsb", "tblsw", "tblsl", 2, 1),
+TBL("tblsnb", "tblsnw", "tblsnl", 2, 0),
+TBL("tblub", "tbluw", "tblul", 0, 1),
+TBL("tblunb", "tblunw", "tblunl", 0, 0),
+
+{"trap", 2,    one(0047100),   one(0177760), "Ts", m68000up | mcfisa_a },
+
+{"trapcc", 2,  one(0052374),   one(0177777), "", m68020up | cpu32 },
+{"trapcs", 2,  one(0052774),   one(0177777), "", m68020up | cpu32 },
+{"trapeq", 2,  one(0053774),   one(0177777), "", m68020up | cpu32 },
+{"trapf", 2,   one(0050774),   one(0177777), "", m68020up | cpu32 | mcfisa_a },
+{"trapge", 2,  one(0056374),   one(0177777), "", m68020up | cpu32 },
+{"trapgt", 2,  one(0057374),   one(0177777), "", m68020up | cpu32 },
+{"traphi", 2,  one(0051374),   one(0177777), "", m68020up | cpu32 },
+{"traple", 2,  one(0057774),   one(0177777), "", m68020up | cpu32 },
+{"trapls", 2,  one(0051774),   one(0177777), "", m68020up | cpu32 },
+{"traplt", 2,  one(0056774),   one(0177777), "", m68020up | cpu32 },
+{"trapmi", 2,  one(0055774),   one(0177777), "", m68020up | cpu32 },
+{"trapne", 2,  one(0053374),   one(0177777), "", m68020up | cpu32 },
+{"trappl", 2,  one(0055374),   one(0177777), "", m68020up | cpu32 },
+{"trapt", 2,   one(0050374),   one(0177777), "", m68020up | cpu32 },
+{"trapvc", 2,  one(0054374),   one(0177777), "", m68020up | cpu32 },
+{"trapvs", 2,  one(0054774),   one(0177777), "", m68020up | cpu32 },
+
+{"trapccw", 4, one(0052372),   one(0177777), "#w", m68020up|cpu32 },
+{"trapcsw", 4, one(0052772),   one(0177777), "#w", m68020up|cpu32 },
+{"trapeqw", 4, one(0053772),   one(0177777), "#w", m68020up|cpu32 },
+{"trapfw", 4,  one(0050772),   one(0177777), "#w", m68020up|cpu32|mcfisa_a},
+{"trapgew", 4, one(0056372),   one(0177777), "#w", m68020up|cpu32 },
+{"trapgtw", 4, one(0057372),   one(0177777), "#w", m68020up|cpu32 },
+{"traphiw", 4, one(0051372),   one(0177777), "#w", m68020up|cpu32 },
+{"traplew", 4, one(0057772),   one(0177777), "#w", m68020up|cpu32 },
+{"traplsw", 4, one(0051772),   one(0177777), "#w", m68020up|cpu32 },
+{"trapltw", 4, one(0056772),   one(0177777), "#w", m68020up|cpu32 },
+{"trapmiw", 4, one(0055772),   one(0177777), "#w", m68020up|cpu32 },
+{"trapnew", 4, one(0053372),   one(0177777), "#w", m68020up|cpu32 },
+{"trapplw", 4, one(0055372),   one(0177777), "#w", m68020up|cpu32 },
+{"traptw", 4,  one(0050372),   one(0177777), "#w", m68020up|cpu32 },
+{"trapvcw", 4, one(0054372),   one(0177777), "#w", m68020up|cpu32 },
+{"trapvsw", 4, one(0054772),   one(0177777), "#w", m68020up|cpu32 },
+
+{"trapccl", 6, one(0052373),   one(0177777), "#l", m68020up|cpu32 },
+{"trapcsl", 6, one(0052773),   one(0177777), "#l", m68020up|cpu32 },
+{"trapeql", 6, one(0053773),   one(0177777), "#l", m68020up|cpu32 },
+{"trapfl", 6,  one(0050773),   one(0177777), "#l", m68020up|cpu32|mcfisa_a},
+{"trapgel", 6, one(0056373),   one(0177777), "#l", m68020up|cpu32 },
+{"trapgtl", 6, one(0057373),   one(0177777), "#l", m68020up|cpu32 },
+{"traphil", 6, one(0051373),   one(0177777), "#l", m68020up|cpu32 },
+{"traplel", 6, one(0057773),   one(0177777), "#l", m68020up|cpu32 },
+{"traplsl", 6, one(0051773),   one(0177777), "#l", m68020up|cpu32 },
+{"trapltl", 6, one(0056773),   one(0177777), "#l", m68020up|cpu32 },
+{"trapmil", 6, one(0055773),   one(0177777), "#l", m68020up|cpu32 },
+{"trapnel", 6, one(0053373),   one(0177777), "#l", m68020up|cpu32 },
+{"trappll", 6, one(0055373),   one(0177777), "#l", m68020up|cpu32 },
+{"traptl", 6,  one(0050373),   one(0177777), "#l", m68020up|cpu32 },
+{"trapvcl", 6, one(0054373),   one(0177777), "#l", m68020up|cpu32 },
+{"trapvsl", 6, one(0054773),   one(0177777), "#l", m68020up|cpu32 },
+
+{"trapv", 2,   one(0047166),   one(0177777), "", m68000up },
+
+{"tstb", 2,    one(0045000),   one(0177700), ";b", m68020up|cpu32|mcfisa_a },
+{"tstb", 2,    one(0045000),   one(0177700), "$b", m68000up },
+{"tstw", 2,    one(0045100),   one(0177700), "*w", m68020up|cpu32|mcfisa_a },
+{"tstw", 2,    one(0045100),   one(0177700), "$w", m68000up },
+{"tstl", 2,    one(0045200),   one(0177700), "*l", m68020up|cpu32|mcfisa_a },
+{"tstl", 2,    one(0045200),   one(0177700), "$l", m68000up },
+
+{"unlk", 2,    one(0047130),   one(0177770), "As", m68000up | mcfisa_a },
+
+{"unpk", 4,    one(0100600),   one(0170770), "DsDd#w", m68020up },
+{"unpk", 4,    one(0100610),   one(0170770), "-s-d#w", m68020up },
+
+{"wddatab", 2, one(0175400),   one(0177700), "~s", mcfisa_a },
+{"wddataw", 2, one(0175500),   one(0177700), "~s", mcfisa_a },
+{"wddatal", 2, one(0175600),   one(0177700), "~s", mcfisa_a },
+
+{"wdebug", 4,  two(0175720, 03),       two(0177770, 0xffff), "as", mcfisa_a },
+{"wdebug", 4,  two(0175750, 03),       two(0177770, 0xffff), "ds", mcfisa_a },
+};
+
+const int m68k_numopcodes = sizeof m68k_opcodes / sizeof m68k_opcodes[0];
+
+/* These aliases used to be in the above table, each one duplicating
+   all of the entries for its primary exactly.  This table was
+   constructed by mechanical processing of the opcode table, with a
+   small number of tweaks done by hand.  There are probably a lot more
+   aliases above that could be moved down here, except for very minor
+   differences.  */
+
+const struct m68k_opcode_alias m68k_opcode_aliases[] =
+{
+  { "add",     "addw", },
+  { "adda",    "addaw", },
+  { "addi",    "addiw", },
+  { "addq",    "addqw", },
+  { "addx",    "addxw", },
+  { "asl",     "aslw", },
+  { "asr",     "asrw", },
+  { "bhi",     "bhiw", },
+  { "bls",     "blsw", },
+  { "bcc",     "bccw", },
+  { "bcs",     "bcsw", },
+  { "bne",     "bnew", },
+  { "beq",     "beqw", },
+  { "bvc",     "bvcw", },
+  { "bvs",     "bvsw", },
+  { "bpl",     "bplw", },
+  { "bmi",     "bmiw", },
+  { "bge",     "bgew", },
+  { "blt",     "bltw", },
+  { "bgt",     "bgtw", },
+  { "ble",     "blew", },
+  { "bra",     "braw", },
+  { "bsr",     "bsrw", },
+  { "bhib",    "bhis", },
+  { "blsb",    "blss", },
+  { "bccb",    "bccs", },
+  { "bcsb",    "bcss", },
+  { "bneb",    "bnes", },
+  { "beqb",    "beqs", },
+  { "bvcb",    "bvcs", },
+  { "bvsb",    "bvss", },
+  { "bplb",    "bpls", },
+  { "bmib",    "bmis", },
+  { "bgeb",    "bges", },
+  { "bltb",    "blts", },
+  { "bgtb",    "bgts", },
+  { "bleb",    "bles", },
+  { "brab",    "bras", },
+  { "bsrb",    "bsrs", },
+  { "bhs",     "bccw" },
+  { "bhss",    "bccs" },
+  { "bhsb",    "bccs" },
+  { "bhsw",    "bccw" },
+  { "bhsl",    "bccl" },
+  { "blo",     "bcsw" },
+  { "blos",    "bcss" },
+  { "blob",    "bcss" },
+  { "blow",    "bcsw" },
+  { "blol",    "bcsl" },
+  { "br",      "braw", },
+  { "brs",     "bras", },
+  { "brb",     "bras", },
+  { "brw",     "braw", },
+  { "brl",     "bral", },
+  { "jfnlt",   "bcc", },       /* Apparently a sun alias.  */
+  { "jfngt",   "ble", },       /* Apparently a sun alias.  */
+  { "jfeq",    "beqs", },      /* Apparently a sun alias.  */
+  { "bchgb",   "bchg", },
+  { "bchgl",   "bchg", },
+  { "bclrb",   "bclr", },
+  { "bclrl",   "bclr", },
+  { "bsetb",   "bset", },
+  { "bsetl",   "bset", },
+  { "btstb",   "btst", },
+  { "btstl",   "btst", },
+  { "cas2",    "cas2w", },
+  { "cas",     "casw", },
+  { "chk2",    "chk2w", },
+  { "chk",     "chkw", },
+  { "clr",     "clrw", },
+  { "cmp2",    "cmp2w", },
+  { "cmpa",    "cmpaw", },
+  { "cmpi",    "cmpiw", },
+  { "cmpm",    "cmpmw", },
+  { "cmp",     "cmpw", },
+  { "dbccw",   "dbcc", },
+  { "dbcsw",   "dbcs", },
+  { "dbeqw",   "dbeq", },
+  { "dbfw",    "dbf", },
+  { "dbgew",   "dbge", },
+  { "dbgtw",   "dbgt", },
+  { "dbhiw",   "dbhi", },
+  { "dblew",   "dble", },
+  { "dblsw",   "dbls", },
+  { "dbltw",   "dblt", },
+  { "dbmiw",   "dbmi", },
+  { "dbnew",   "dbne", },
+  { "dbplw",   "dbpl", },
+  { "dbtw",    "dbt", },
+  { "dbvcw",   "dbvc", },
+  { "dbvsw",   "dbvs", },
+  { "dbhs",    "dbcc", },
+  { "dbhsw",   "dbcc", },
+  { "dbra",    "dbf", },
+  { "dbraw",   "dbf", },
+  { "tdivsl",  "divsl", },
+  { "divs",    "divsw", },
+  { "divu",    "divuw", },
+  { "ext",     "extw", },
+  { "extbw",   "extw", },
+  { "extwl",   "extl", },
+  { "fbneq",   "fbne", },
+  { "fbsneq",  "fbsne", },
+  { "fdbneq",  "fdbne", },
+  { "fdbsneq", "fdbsne", },
+  { "fmovecr", "fmovecrx", },
+  { "fmovm",   "fmovem", },
+  { "fsneq",   "fsne", },
+  { "fssneq",  "fssne", },
+  { "ftrapneq",        "ftrapne", },
+  { "ftrapsneq", "ftrapsne", },
+  { "fjneq",   "fjne", },
+  { "fjsneq",  "fjsne", },
+  { "jmpl",    "jmp", },
+  { "jmps",    "jmp", },
+  { "jsrl",    "jsr", },
+  { "jsrs",    "jsr", },
+  { "leal",    "lea", },
+  { "lsl",     "lslw", },
+  { "lsr",     "lsrw", },
+  { "mac",     "macw" },
+  { "movea",   "moveaw", },
+  { "movem",   "movemw", },
+  { "movml",   "moveml", },
+  { "movmw",   "movemw", },
+  { "movm",    "movemw", },
+  { "movep",   "movepw", },
+  { "movpw",   "movepw", },
+  { "moves",   "movesw" },
+  { "muls",    "mulsw", },
+  { "mulu",    "muluw", },
+  { "msac",    "msacw" },
+  { "nbcdb",   "nbcd" },
+  { "neg",     "negw", },
+  { "negx",    "negxw", },
+  { "not",     "notw", },
+  { "peal",    "pea", },
+  { "rol",     "rolw", },
+  { "ror",     "rorw", },
+  { "roxl",    "roxlw", },
+  { "roxr",    "roxrw", },
+  { "sats",    "satsl", },
+  { "sbcdb",   "sbcd", },
+  { "sccb",    "scc", },
+  { "scsb",    "scs", },
+  { "seqb",    "seq", },
+  { "sfb",     "sf", },
+  { "sgeb",    "sge", },
+  { "sgtb",    "sgt", },
+  { "shib",    "shi", },
+  { "sleb",    "sle", },
+  { "slsb",    "sls", },
+  { "sltb",    "slt", },
+  { "smib",    "smi", },
+  { "sneb",    "sne", },
+  { "splb",    "spl", },
+  { "stb",     "st", },
+  { "svcb",    "svc", },
+  { "svsb",    "svs", },
+  { "sfge",    "sge", },
+  { "sfgt",    "sgt", },
+  { "sfle",    "sle", },
+  { "sflt",    "slt", },
+  { "sfneq",   "sne", },
+  { "suba",    "subaw", },
+  { "subi",    "subiw", },
+  { "subq",    "subqw", },
+  { "sub",     "subw", },
+  { "subx",    "subxw", },
+  { "swapw",   "swap", },
+  { "tasb",    "tas", },
+  { "tpcc",    "trapcc", },
+  { "tcc",     "trapcc", },
+  { "tst",     "tstw", },
+  { "jbra",    "jra", },
+  { "jbhi",    "jhi", },
+  { "jbls",    "jls", },
+  { "jbcc",    "jcc", },
+  { "jbcs",    "jcs", },
+  { "jbne",    "jne", },
+  { "jbeq",    "jeq", },
+  { "jbvc",    "jvc", },
+  { "jbvs",    "jvs", },
+  { "jbpl",    "jpl", },
+  { "jbmi",    "jmi", },
+  { "jbge",    "jge", },
+  { "jblt",    "jlt", },
+  { "jbgt",    "jgt", },
+  { "jble",    "jle", },
+  { "movql",   "moveq", },
+  { "moveql",  "moveq", },
+  { "movl",    "movel", },
+  { "movq",    "moveq", },
+  { "moval",   "moveal", },
+  { "movaw",   "moveaw", },
+  { "movb",    "moveb", },
+  { "movc",    "movec", },
+  { "movecl",  "movec", },
+  { "movpl",   "movepl", },
+  { "movw",    "movew", },
+  { "movsb",   "movesb", },
+  { "movsl",   "movesl", },
+  { "movsw",   "movesw", },
+  { "mov3q",   "mov3ql", },
+
+  { "tdivul",  "divul", },     /* For m68k-svr4.  */
+  { "fmovb",   "fmoveb", },
+  { "fsmovb",  "fsmoveb", },
+  { "fdmovb",  "fdmoveb", },
+  { "fmovd",   "fmoved", },
+  { "fsmovd",  "fsmoved", },
+  { "fmovl",   "fmovel", },
+  { "fsmovl",  "fsmovel", },
+  { "fdmovl",  "fdmovel", },
+  { "fmovp",   "fmovep", },
+  { "fsmovp",  "fsmovep", },
+  { "fdmovp",  "fdmovep", },
+  { "fmovs",   "fmoves", },
+  { "fsmovs",  "fsmoves", },
+  { "fdmovs",  "fdmoves", },
+  { "fmovw",   "fmovew", },
+  { "fsmovw",  "fsmovew", },
+  { "fdmovw",  "fdmovew", },
+  { "fmovx",   "fmovex", },
+  { "fsmovx",  "fsmovex", },
+  { "fdmovx",  "fdmovex", },
+  { "fmovcr",  "fmovecr", },
+  { "fmovcrx", "fmovecrx", },
+  { "ftestb",  "ftstb", },
+  { "ftestd",  "ftstd", },
+  { "ftestl",  "ftstl", },
+  { "ftestp",  "ftstp", },
+  { "ftests",  "ftsts", },
+  { "ftestw",  "ftstw", },
+  { "ftestx",  "ftstx", },
+
+  { "bitrevl",  "bitrev", },
+  { "byterevl", "byterev", },
+  { "ff1l",     "ff1", },
+
+};
+
+const int m68k_numaliases =
+  sizeof m68k_opcode_aliases / sizeof m68k_opcode_aliases[0];
+/* **** End of m68k-opc.c */
+/* **** floatformat.c from sourceware.org CVS 2005-08-14.  */
+/* IEEE floating point support routines, for GDB, the GNU Debugger.
+   Copyright (C) 1991, 1994, 1999, 2000, 2003 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+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.  */
+
+/* This is needed to pick up the NAN macro on some systems.  */
+//#define _GNU_SOURCE
+
+#ifndef INFINITY
+#ifdef HUGE_VAL
+#define INFINITY HUGE_VAL
+#else
+#define INFINITY (1.0 / 0.0)
+#endif
+#endif
+
+#ifndef NAN
+#define NAN (0.0 / 0.0)
+#endif
+
+static unsigned long get_field (const unsigned char *,
+                                enum floatformat_byteorders,
+                                unsigned int,
+                                unsigned int,
+                                unsigned int);
+static int floatformat_always_valid (const struct floatformat *fmt,
+                                     const char *from);
+
+static int
+floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED,
+                          const char *from ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
+
+/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not
+   going to bother with trying to muck around with whether it is defined in
+   a system header, what we do if not, etc.  */
+#define FLOATFORMAT_CHAR_BIT 8
+
+/* floatformats for IEEE single and double, big and little endian.  */
+const struct floatformat floatformat_ieee_single_big =
+{
+  floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23,
+  floatformat_intbit_no,
+  "floatformat_ieee_single_big",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_ieee_single_little =
+{
+  floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23,
+  floatformat_intbit_no,
+  "floatformat_ieee_single_little",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_ieee_double_big =
+{
+  floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52,
+  floatformat_intbit_no,
+  "floatformat_ieee_double_big",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_ieee_double_little =
+{
+  floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52,
+  floatformat_intbit_no,
+  "floatformat_ieee_double_little",
+  floatformat_always_valid
+};
+
+/* floatformat for IEEE double, little endian byte order, with big endian word
+   ordering, as on the ARM.  */
+
+const struct floatformat floatformat_ieee_double_littlebyte_bigword =
+{
+  floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52,
+  floatformat_intbit_no,
+  "floatformat_ieee_double_littlebyte_bigword",
+  floatformat_always_valid
+};
+
+static int floatformat_i387_ext_is_valid (const struct floatformat *fmt, const char *from);
+
+static int
+floatformat_i387_ext_is_valid (const struct floatformat *fmt, const char *from)
+{
+  /* In the i387 double-extended format, if the exponent is all ones,
+     then the integer bit must be set.  If the exponent is neither 0
+     nor ~0, the intbit must also be set.  Only if the exponent is
+     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
+    return 1;
+}
+
+const struct floatformat floatformat_i387_ext =
+{
+  floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
+  floatformat_intbit_yes,
+  "floatformat_i387_ext",
+  floatformat_i387_ext_is_valid
+};
+const struct floatformat floatformat_m68881_ext =
+{
+  /* Note that the bits from 16 to 31 are unused.  */
+  floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64,
+  floatformat_intbit_yes,
+  "floatformat_m68881_ext",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_i960_ext =
+{
+  /* Note that the bits from 0 to 15 are unused.  */
+  floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
+  floatformat_intbit_yes,
+  "floatformat_i960_ext",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_m88110_ext =
+{
+  floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
+  floatformat_intbit_yes,
+  "floatformat_m88110_ext",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_m88110_harris_ext =
+{
+  /* Harris uses raw format 128 bytes long, but the number is just an ieee
+     double, and the last 64 bits are wasted. */
+  floatformat_big,128, 0, 1, 11,  0x3ff,  0x7ff, 12, 52,
+  floatformat_intbit_no,
+  "floatformat_m88110_ext_harris",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_arm_ext_big =
+{
+  /* Bits 1 to 16 are unused.  */
+  floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
+  floatformat_intbit_yes,
+  "floatformat_arm_ext_big",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_arm_ext_littlebyte_bigword =
+{
+  /* Bits 1 to 16 are unused.  */
+  floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
+  floatformat_intbit_yes,
+  "floatformat_arm_ext_littlebyte_bigword",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_ia64_spill_big =
+{
+  floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
+  floatformat_intbit_yes,
+  "floatformat_ia64_spill_big",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_ia64_spill_little =
+{
+  floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
+  floatformat_intbit_yes,
+  "floatformat_ia64_spill_little",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_ia64_quad_big =
+{
+  floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
+  floatformat_intbit_no,
+  "floatformat_ia64_quad_big",
+  floatformat_always_valid
+};
+const struct floatformat floatformat_ia64_quad_little =
+{
+  floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
+  floatformat_intbit_no,
+  "floatformat_ia64_quad_little",
+  floatformat_always_valid
+};
+\f
+/* Extract a field which starts at START and is LEN bits long.  DATA and
+   TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
+static unsigned long
+get_field (const unsigned char *data, enum floatformat_byteorders order,
+           unsigned int total_len, unsigned int start, unsigned int len)
+{
+  unsigned long result;
+  unsigned int cur_byte;
+  int cur_bitshift;
+
+  /* Start at the least significant part of the field.  */
+  cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
+  if (order == floatformat_little)
+    cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
+  cur_bitshift =
+    ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
+  result = *(data + cur_byte) >> (-cur_bitshift);
+  cur_bitshift += FLOATFORMAT_CHAR_BIT;
+  if (order == floatformat_little)
+    ++cur_byte;
+  else
+    --cur_byte;
+
+  /* Move towards the most significant part of the field.  */
+  while ((unsigned int) cur_bitshift < len)
+    {
+      if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
+       /* This is the last byte; zero out the bits which are not part of
+          this field.  */
+       result |=
+         (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1))
+           << cur_bitshift;
+      else
+       result |= *(data + cur_byte) << cur_bitshift;
+      cur_bitshift += FLOATFORMAT_CHAR_BIT;
+      if (order == floatformat_little)
+       ++cur_byte;
+      else
+       --cur_byte;
+    }
+  return result;
+}
+  
+#ifndef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* Convert from FMT to a double.
+   FROM is the address of the extended float.
+   Store the double in *TO.  */
+
+void
+floatformat_to_double (const struct floatformat *fmt,
+                       const char *from, double *to)
+{
+  const unsigned char *ufrom = (const unsigned char *)from;
+  double dto;
+  long exponent;
+  unsigned long mant;
+  unsigned int mant_bits, mant_off;
+  int mant_bits_left;
+  int special_exponent;                /* It's a NaN, denorm or zero */
+
+  exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
+                       fmt->exp_start, fmt->exp_len);
+
+  /* If the exponent indicates a NaN, we don't have information to
+     decide what to do.  So we handle it like IEEE, except that we
+     don't try to preserve the type of NaN.  FIXME.  */
+  if ((unsigned long) exponent == fmt->exp_nan)
+    {
+      int nan;
+
+      mant_off = fmt->man_start;
+      mant_bits_left = fmt->man_len;
+      nan = 0;
+      while (mant_bits_left > 0)
+       {
+         mant_bits = min (mant_bits_left, 32);
+
+         if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
+                        mant_off, mant_bits) != 0)
+           {
+             /* This is a NaN.  */
+             nan = 1;
+             break;
+           }
+
+         mant_off += mant_bits;
+         mant_bits_left -= mant_bits;
+       }
+
+      /* On certain systems (such as GNU/Linux), the use of the
+        INFINITY macro below may generate a warning that can not be
+        silenced due to a bug in GCC (PR preprocessor/11931).  The
+        preprocessor fails to recognise the __extension__ keyword in
+        conjunction with the GNU/C99 extension for hexadecimal
+        floating point constants and will issue a warning when
+        compiling with -pedantic.  */
+      if (nan)
+       dto = NAN;
+      else
+       dto = INFINITY;
+
+      if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
+       dto = -dto;
+
+      *to = dto;
+
+      return;
+    }
+
+  mant_bits_left = fmt->man_len;
+  mant_off = fmt->man_start;
+  dto = 0.0;
+
+  special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan;
+
+  /* Don't bias zero's, denorms or NaNs.  */
+  if (!special_exponent)
+    exponent -= fmt->exp_bias;
+
+  /* Build the result algebraically.  Might go infinite, underflow, etc;
+     who cares. */
+
+  /* If this format uses a hidden bit, explicitly add it in now.  Otherwise,
+     increment the exponent by one to account for the integer bit.  */
+
+  if (!special_exponent)
+    {
+      if (fmt->intbit == floatformat_intbit_no)
+       dto = ldexp (1.0, exponent);
+      else
+       exponent++;
+    }
+
+  while (mant_bits_left > 0)
+    {
+      mant_bits = min (mant_bits_left, 32);
+
+      mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
+                        mant_off, mant_bits);
+
+      /* Handle denormalized numbers.  FIXME: What should we do for
+        non-IEEE formats?  */
+      if (exponent == 0 && mant != 0)
+       dto += ldexp ((double)mant,
+                     (- fmt->exp_bias
+                      - mant_bits
+                      - (mant_off - fmt->man_start)
+                      + 1));
+      else
+       dto += ldexp ((double)mant, exponent - mant_bits);
+      if (exponent != 0)
+       exponent -= mant_bits;
+      mant_off += mant_bits;
+      mant_bits_left -= mant_bits;
+    }
+
+  /* Negate it if negative.  */
+  if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
+    dto = -dto;
+  *to = dto;
+}
+\f
+static void put_field (unsigned char *, enum floatformat_byteorders,
+                       unsigned int,
+                       unsigned int,
+                       unsigned int,
+                       unsigned long);
+
+/* Set a field which starts at START and is LEN bits long.  DATA and
+   TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER.  */
+static void
+put_field (unsigned char *data, enum floatformat_byteorders order,
+           unsigned int total_len, unsigned int start, unsigned int len,
+           unsigned long stuff_to_put)
+{
+  unsigned int cur_byte;
+  int cur_bitshift;
+
+  /* Start at the least significant part of the field.  */
+  cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
+  if (order == floatformat_little)
+    cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
+  cur_bitshift =
+    ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
+  *(data + cur_byte) &=
+    ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift));
+  *(data + cur_byte) |=
+    (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
+  cur_bitshift += FLOATFORMAT_CHAR_BIT;
+  if (order == floatformat_little)
+    ++cur_byte;
+  else
+    --cur_byte;
+
+  /* Move towards the most significant part of the field.  */
+  while ((unsigned int) cur_bitshift < len)
+    {
+      if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
+       {
+         /* This is the last byte.  */
+         *(data + cur_byte) &=
+           ~((1 << (len - cur_bitshift)) - 1);
+         *(data + cur_byte) |= (stuff_to_put >> cur_bitshift);
+       }
+      else
+       *(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
+                             & ((1 << FLOATFORMAT_CHAR_BIT) - 1));
+      cur_bitshift += FLOATFORMAT_CHAR_BIT;
+      if (order == floatformat_little)
+       ++cur_byte;
+      else
+       --cur_byte;
+    }
+}
+
+/* The converse: convert the double *FROM to an extended float
+   and store where TO points.  Neither FROM nor TO have any alignment
+   restrictions.  */
+
+void
+floatformat_from_double (const struct floatformat *fmt,
+                         const double *from, char *to)
+{
+  double dfrom;
+  int exponent;
+  double mant;
+  unsigned int mant_bits, mant_off;
+  int mant_bits_left;
+  unsigned char *uto = (unsigned char *)to;
+
+  dfrom = *from;
+  memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
+
+  /* If negative, set the sign bit.  */
+  if (dfrom < 0)
+    {
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
+      dfrom = -dfrom;
+    }
+
+  if (dfrom == 0)
+    {
+      /* 0.0.  */
+      return;
+    }
+
+  if (dfrom != dfrom)
+    {
+      /* NaN.  */
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+                fmt->exp_len, fmt->exp_nan);
+      /* Be sure it's not infinity, but NaN value is irrelevant.  */
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
+                32, 1);
+      return;
+    }
+
+  if (dfrom + dfrom == dfrom)
+    {
+      /* This can only happen for an infinite value (or zero, which we
+        already handled above).  */
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+                fmt->exp_len, fmt->exp_nan);
+      return;
+    }
+
+  mant = frexp (dfrom, &exponent);
+  if (exponent + fmt->exp_bias - 1 > 0)
+    put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+              fmt->exp_len, exponent + fmt->exp_bias - 1);
+  else
+    {
+      /* Handle a denormalized number.  FIXME: What should we do for
+        non-IEEE formats?  */
+      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+                fmt->exp_len, 0);
+      mant = ldexp (mant, exponent + fmt->exp_bias - 1);
+    }
+
+  mant_bits_left = fmt->man_len;
+  mant_off = fmt->man_start;
+  while (mant_bits_left > 0)
+    {
+      unsigned long mant_long;
+      mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
+
+      mant *= 4294967296.0;
+      mant_long = (unsigned long)mant;
+      mant -= mant_long;
+
+      /* If the integer bit is implicit, and we are not creating a
+        denormalized number, then we need to discard it.  */
+      if ((unsigned int) mant_bits_left == fmt->man_len
+         && fmt->intbit == floatformat_intbit_no
+         && exponent + fmt->exp_bias - 1 > 0)
+       {
+         mant_long &= 0x7fffffff;
+         mant_bits -= 1;
+       }
+      else if (mant_bits < 32)
+       {
+         /* The bits we want are in the most significant MANT_BITS bits of
+            mant_long.  Move them to the least significant.  */
+         mant_long >>= 32 - mant_bits;
+       }
+
+      put_field (uto, fmt->byteorder, fmt->totalsize,
+                mant_off, mant_bits, mant_long);
+      mant_off += mant_bits;
+      mant_bits_left -= mant_bits;
+    }
+}
+
+/* Return non-zero iff the data at FROM is a valid number in format FMT.  */
+
+int
+floatformat_is_valid (const struct floatformat *fmt, const char *from)
+{
+  return fmt->is_valid (fmt, from);
+}
+
+
+#ifdef IEEE_DEBUG
+
+/* This is to be run on a host which uses IEEE floating point.  */
+
+void
+ieee_test (double n)
+{
+  double result;
+
+  floatformat_to_double (&floatformat_ieee_double_little, (char *) &n,
+                        &result);
+  if ((n != result && (! isnan (n) || ! isnan (result)))
+      || (n < 0 && result >= 0)
+      || (n >= 0 && result < 0))
+    printf ("Differ(to): %.20g -> %.20g\n", n, result);
+
+  floatformat_from_double (&floatformat_ieee_double_little, &n,
+                          (char *) &result);
+  if ((n != result && (! isnan (n) || ! isnan (result)))
+      || (n < 0 && result >= 0)
+      || (n >= 0 && result < 0))
+    printf ("Differ(from): %.20g -> %.20g\n", n, result);
+
+#if 0
+  {
+    char exten[16];
+
+    floatformat_from_double (&floatformat_m68881_ext, &n, exten);
+    floatformat_to_double (&floatformat_m68881_ext, exten, &result);
+    if (n != result)
+      printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
+  }
+#endif
+
+#if IEEE_DEBUG > 1
+  /* This is to be run on a host which uses 68881 format.  */
+  {
+    long double ex = *(long double *)exten;
+    if (ex != n)
+      printf ("Differ(from vs. extended): %.20g\n", n);
+  }
+#endif
+}
+
+int
+main (void)
+{
+  ieee_test (0.0);
+  ieee_test (0.5);
+  ieee_test (256.0);
+  ieee_test (0.12345);
+  ieee_test (234235.78907234);
+  ieee_test (-512.0);
+  ieee_test (-0.004321);
+  ieee_test (1.2E-70);
+  ieee_test (1.2E-316);
+  ieee_test (4.9406564584124654E-324);
+  ieee_test (- 4.9406564584124654E-324);
+  ieee_test (- 0.0);
+  ieee_test (- INFINITY);
+  ieee_test (- NAN);
+  ieee_test (INFINITY);
+  ieee_test (NAN);
+  return 0;
+}
+#endif
+/* **** End of floatformat.c  */
index fbc64c7..f612895 100644 (file)
@@ -2155,10 +2155,6 @@ struct mips_opcode *mips_opcodes =
 int bfd_mips_num_opcodes = MIPS_NUM_OPCODES;
 #undef MIPS_NUM_OPCODES
 
-typedef int bfd_boolean;
-#define TRUE (1)
-#define FALSE (0)
-
 /* Mips instructions are at maximum this many bytes long.  */
 #define INSNLEN 4
 
index 1ff9bde..d7acaa4 100644 (file)
@@ -64,6 +64,8 @@ static int term_outbuf_index;
 
 static void monitor_start_input(void);
 
+CPUState *mon_cpu = NULL;
+
 void term_flush(void)
 {
     if (term_outbuf_index > 0) {
@@ -196,39 +198,82 @@ static void do_info_version(void)
   term_printf("%s\n", QEMU_VERSION);
 }
 
-static void do_info_network(void)
+static void do_info_block(void)
 {
-    int i, j;
-    NetDriverState *nd;
-    
-    for(i = 0; i < nb_nics; i++) {
-        nd = &nd_table[i];
-        term_printf("%d: ifname=%s macaddr=", i, nd->ifname);
-        for(j = 0; j < 6; j++) {
-            if (j > 0)
-                term_printf(":");
-            term_printf("%02x", nd->macaddr[j]);
+    bdrv_info();
+}
+
+/* get the current CPU defined by the user */
+int mon_set_cpu(int cpu_index)
+{
+    CPUState *env;
+
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        if (env->cpu_index == cpu_index) {
+            mon_cpu = env;
+            return 0;
         }
-        term_printf("\n");
     }
+    return -1;
 }
-static void do_info_block(void)
+
+CPUState *mon_get_cpu(void)
 {
-    bdrv_info();
+    if (!mon_cpu) {
+        mon_set_cpu(0);
+    }
+    return mon_cpu;
 }
 
 static void do_info_registers(void)
 {
+    CPUState *env;
+    env = mon_get_cpu();
+    if (!env)
+        return;
 #ifdef TARGET_I386
-    cpu_dump_state(cpu_single_env, NULL, monitor_fprintf,
+    cpu_dump_state(env, NULL, monitor_fprintf,
                    X86_DUMP_FPU);
 #else
-    cpu_dump_state(cpu_single_env, NULL, monitor_fprintf, 
+    cpu_dump_state(env, NULL, monitor_fprintf, 
                    0);
 #endif
 }
 
+static void do_info_cpus(void)
+{
+    CPUState *env;
+
+    /* just to set the default cpu if not already done */
+    mon_get_cpu();
+
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        term_printf("%c CPU #%d:", 
+                    (env == mon_cpu) ? '*' : ' ',
+                    env->cpu_index);
+#if defined(TARGET_I386)
+        term_printf(" pc=0x" TARGET_FMT_lx, env->eip + env->segs[R_CS].base);
+        if (env->hflags & HF_HALTED_MASK)
+            term_printf(" (halted)");
+#elif defined(TARGET_PPC)
+        term_printf(" nip=0x" TARGET_FMT_lx, env->nip);
+        if (env->halted)
+            term_printf(" (halted)");
+#elif defined(TARGET_SPARC)
+        term_printf(" pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx, env->pc, env->npc);
+        if (env->halted)
+            term_printf(" (halted)");
+#endif
+        term_printf("\n");
+    }
+}
+
+static void do_cpu_set(int index)
+{
+    if (mon_set_cpu(index) < 0)
+        term_printf("Invalid CPU index\n");
+}
+
 static void do_info_jit(void)
 {
     dump_exec_info(NULL, monitor_fprintf);
@@ -398,6 +443,7 @@ static void term_printc(int c)
 static void memory_dump(int count, int format, int wsize, 
                         target_ulong addr, int is_physical)
 {
+    CPUState *env;
     int nb_per_line, l, line_size, i, max_digits, len;
     uint8_t buf[16];
     uint64_t v;
@@ -405,19 +451,22 @@ static void memory_dump(int count, int format, int wsize,
     if (format == 'i') {
         int flags;
         flags = 0;
+        env = mon_get_cpu();
+        if (!env && !is_physical)
+            return;
 #ifdef TARGET_I386
         if (wsize == 2) {
             flags = 1;
         } else if (wsize == 4) {
             flags = 0;
         } else {
-            /* as default we use the current CS size */
+                /* as default we use the current CS size */
             flags = 0;
-            if (!(cpu_single_env->segs[R_CS].flags & DESC_B_MASK))
+            if (env && !(env->segs[R_CS].flags & DESC_B_MASK))
                 flags = 1;
         }
 #endif
-        monitor_disas(addr, count, is_physical, flags);
+        monitor_disas(env, addr, count, is_physical, flags);
         return;
     }
 
@@ -454,7 +503,10 @@ static void memory_dump(int count, int format, int wsize,
         if (is_physical) {
             cpu_physical_memory_rw(addr, buf, l, 0);
         } else {
-            cpu_memory_rw_debug(cpu_single_env, addr, buf, l, 0);
+            env = mon_get_cpu();
+            if (!env)
+                break;
+            cpu_memory_rw_debug(env, addr, buf, l, 0);
         }
         i = 0; 
         while (i < l) {
@@ -793,10 +845,14 @@ static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask)
 
 static void tlb_info(void)
 {
-    CPUState *env = cpu_single_env;
+    CPUState *env;
     int l1, l2;
     uint32_t pgd, pde, pte;
 
+    env = mon_get_cpu();
+    if (!env)
+        return;
+
     if (!(env->cr[0] & CR0_PG_MASK)) {
         term_printf("PG disabled\n");
         return;
@@ -847,10 +903,14 @@ static void mem_print(uint32_t *pstart, int *plast_prot,
 
 static void mem_info(void)
 {
-    CPUState *env = cpu_single_env;
+    CPUState *env;
     int l1, l2, prot, last_prot;
     uint32_t pgd, pde, pte, start, end;
 
+    env = mon_get_cpu();
+    if (!env)
+        return;
+
     if (!(env->cr[0] & CR0_PG_MASK)) {
         term_printf("PG disabled\n");
         return;
@@ -891,17 +951,21 @@ static void mem_info(void)
 static void do_info_kqemu(void)
 {
 #ifdef USE_KQEMU
+    CPUState *env;
     int val;
     val = 0;
-    if (cpu_single_env)
-        val = cpu_single_env->kqemu_enabled;
+    env = mon_get_cpu();
+    if (!env) {
+        term_printf("No cpu initialized yet");
+        return;
+    }
+    val = env->kqemu_enabled;
     term_printf("kqemu is %s\n", val ? "enabled" : "disabled");
 #else
     term_printf("kqemu support is not compiled\n");
 #endif
 } 
 
-
 static term_cmd_t term_cmds[] = {
     { "help|?", "s?", do_help, 
       "[cmd]", "show the help" },
@@ -948,6 +1012,12 @@ static term_cmd_t term_cmds[] = {
       "", "send system power down event" },
     { "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, 
+      "index", "set the default CPU" },
     { NULL, NULL, }, 
 };
 
@@ -960,6 +1030,8 @@ static term_cmd_t info_cmds[] = {
       "", "show the block devices" },
     { "registers", "", do_info_registers,
       "", "show the cpu registers" },
+    { "cpus", "", do_info_cpus,
+      "", "show infos for each CPU" },
     { "history", "", do_info_history,
       "", "show the command line history", },
     { "irq", "", irq_info,
@@ -978,6 +1050,10 @@ static term_cmd_t info_cmds[] = {
       "", "show dynamic compiler info", },
     { "kqemu", "", do_info_kqemu,
       "", "show kqemu information", },
+    { "usb", "", usb_info,
+      "", "show guest USB devices", },
+    { "usbhost", "", usb_host_info,
+      "", "show host USB devices", },
     { NULL, NULL, },
 };
 
@@ -999,75 +1075,105 @@ typedef struct MonitorDef {
 #if defined(TARGET_I386)
 static target_long monitor_get_pc (struct MonitorDef *md, int val)
 {
-    return cpu_single_env->eip + cpu_single_env->segs[R_CS].base;
+    CPUState *env = mon_get_cpu();
+    if (!env)
+        return 0;
+    return env->eip + env->segs[R_CS].base;
 }
 #endif
 
 #if defined(TARGET_PPC)
 static target_long monitor_get_ccr (struct MonitorDef *md, int val)
 {
+    CPUState *env = mon_get_cpu();
     unsigned int u;
     int i;
 
+    if (!env)
+        return 0;
+
     u = 0;
     for (i = 0; i < 8; i++)
-       u |= cpu_single_env->crf[i] << (32 - (4 * i));
+       u |= env->crf[i] << (32 - (4 * i));
 
     return u;
 }
 
 static target_long monitor_get_msr (struct MonitorDef *md, int val)
 {
-    return (cpu_single_env->msr[MSR_POW] << MSR_POW) |
-        (cpu_single_env->msr[MSR_ILE] << MSR_ILE) |
-        (cpu_single_env->msr[MSR_EE] << MSR_EE) |
-        (cpu_single_env->msr[MSR_PR] << MSR_PR) |
-        (cpu_single_env->msr[MSR_FP] << MSR_FP) |
-        (cpu_single_env->msr[MSR_ME] << MSR_ME) |
-        (cpu_single_env->msr[MSR_FE0] << MSR_FE0) |
-        (cpu_single_env->msr[MSR_SE] << MSR_SE) |
-        (cpu_single_env->msr[MSR_BE] << MSR_BE) |
-        (cpu_single_env->msr[MSR_FE1] << MSR_FE1) |
-        (cpu_single_env->msr[MSR_IP] << MSR_IP) |
-        (cpu_single_env->msr[MSR_IR] << MSR_IR) |
-        (cpu_single_env->msr[MSR_DR] << MSR_DR) |
-        (cpu_single_env->msr[MSR_RI] << MSR_RI) |
-        (cpu_single_env->msr[MSR_LE] << MSR_LE);
+    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);
 }
 
 static target_long monitor_get_xer (struct MonitorDef *md, int val)
 {
-    return (cpu_single_env->xer[XER_SO] << XER_SO) |
-        (cpu_single_env->xer[XER_OV] << XER_OV) |
-        (cpu_single_env->xer[XER_CA] << XER_CA) |
-        (cpu_single_env->xer[XER_BC] << XER_BC);
+    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);
 }
 
 static target_long monitor_get_decr (struct MonitorDef *md, int val)
 {
-    return cpu_ppc_load_decr(cpu_single_env);
+    CPUState *env = mon_get_cpu();
+    if (!env)
+        return 0;
+    return cpu_ppc_load_decr(env);
 }
 
 static target_long monitor_get_tbu (struct MonitorDef *md, int val)
 {
-    return cpu_ppc_load_tbu(cpu_single_env);
+    CPUState *env = mon_get_cpu();
+    if (!env)
+        return 0;
+    return cpu_ppc_load_tbu(env);
 }
 
 static target_long monitor_get_tbl (struct MonitorDef *md, int val)
 {
-    return cpu_ppc_load_tbl(cpu_single_env);
+    CPUState *env = mon_get_cpu();
+    if (!env)
+        return 0;
+    return cpu_ppc_load_tbl(env);
 }
 #endif
 
 #if defined(TARGET_SPARC)
+#ifndef TARGET_SPARC64
 static target_long monitor_get_psr (struct MonitorDef *md, int val)
 {
-    return GET_PSR(cpu_single_env);
+    CPUState *env = mon_get_cpu();
+    if (!env)
+        return 0;
+    return GET_PSR(env);
 }
+#endif
 
 static target_long monitor_get_reg(struct MonitorDef *md, int val)
 {
-    return cpu_single_env->regwptr[val];
+    CPUState *env = mon_get_cpu();
+    if (!env)
+        return 0;
+    return env->regwptr[val];
 }
 #endif
 
@@ -1202,8 +1308,10 @@ static MonitorDef monitor_defs[] = {
     { "pc", offsetof(CPUState, pc) },
     { "npc", offsetof(CPUState, npc) },
     { "y", offsetof(CPUState, y) },
+#ifndef TARGET_SPARC64
     { "psr", 0, &monitor_get_psr, },
     { "wim", offsetof(CPUState, wim) },
+#endif
     { "tbr", offsetof(CPUState, tbr) },
     { "fsr", offsetof(CPUState, fsr) },
     { "f0", offsetof(CPUState, fpr[0]) },
@@ -1238,6 +1346,32 @@ static MonitorDef monitor_defs[] = {
     { "f29", offsetof(CPUState, fpr[29]) },
     { "f30", offsetof(CPUState, fpr[30]) },
     { "f31", offsetof(CPUState, fpr[31]) },
+#ifdef TARGET_SPARC64
+    { "f32", offsetof(CPUState, fpr[32]) },
+    { "f34", offsetof(CPUState, fpr[34]) },
+    { "f36", offsetof(CPUState, fpr[36]) },
+    { "f38", offsetof(CPUState, fpr[38]) },
+    { "f40", offsetof(CPUState, fpr[40]) },
+    { "f42", offsetof(CPUState, fpr[42]) },
+    { "f44", offsetof(CPUState, fpr[44]) },
+    { "f46", offsetof(CPUState, fpr[46]) },
+    { "f48", offsetof(CPUState, fpr[48]) },
+    { "f50", offsetof(CPUState, fpr[50]) },
+    { "f52", offsetof(CPUState, fpr[52]) },
+    { "f54", offsetof(CPUState, fpr[54]) },
+    { "f56", offsetof(CPUState, fpr[56]) },
+    { "f58", offsetof(CPUState, fpr[58]) },
+    { "f60", offsetof(CPUState, fpr[60]) },
+    { "f62", offsetof(CPUState, fpr[62]) },
+    { "asi", offsetof(CPUState, asi) },
+    { "pstate", offsetof(CPUState, pstate) },
+    { "cansave", offsetof(CPUState, cansave) },
+    { "canrestore", offsetof(CPUState, canrestore) },
+    { "otherwin", offsetof(CPUState, otherwin) },
+    { "wstate", offsetof(CPUState, wstate) },
+    { "cleanwin", offsetof(CPUState, cleanwin) },
+    { "fprs", offsetof(CPUState, fprs) },
+#endif
 #endif
     { NULL },
 };
@@ -1249,6 +1383,7 @@ static void expr_error(const char *fmt)
     longjmp(expr_env, 1);
 }
 
+/* return 0 if OK, -1 if not found, -2 if no CPU defined */
 static int get_monitor_def(target_long *pval, const char *name)
 {
     MonitorDef *md;
@@ -1259,7 +1394,10 @@ static int get_monitor_def(target_long *pval, const char *name)
             if (md->get_value) {
                 *pval = md->get_value(md, md->offset);
             } else {
-                ptr = (uint8_t *)cpu_single_env + md->offset;
+                CPUState *env = mon_get_cpu();
+                if (!env)
+                    return -2;
+                ptr = (uint8_t *)env + md->offset;
                 switch(md->type) {
                 case MD_I32:
                     *pval = *(int32_t *)ptr;
@@ -1293,6 +1431,7 @@ static target_long expr_unary(void)
 {
     target_long n;
     char *p;
+    int ret;
 
     switch(*pch) {
     case '+':
@@ -1342,8 +1481,11 @@ static target_long expr_unary(void)
             while (isspace(*pch))
                 pch++;
             *q = 0;
-            if (get_monitor_def(&n, buf))
+            ret = get_monitor_def(&n, buf);
+            if (ret == -1)
                 expr_error("unknown register");
+            else if (ret == -2) 
+                expr_error("no cpu defined");
         }
         break;
     case '\0':
index f6198f4..21c739c 100644 (file)
Binary files a/qemu/pc-bios/proll.elf and b/qemu/pc-bios/proll.elf differ
index 8900253..cc69519 100644 (file)
@@ -1,6 +1,6 @@
-diff -ruN proll_18.orig/Makefile proll-patch10/Makefile
+diff -ruN proll_18.orig/Makefile proll-patch-15/Makefile
 --- proll_18.orig/Makefile     2002-09-13 14:16:59.000000000 +0000
-+++ proll-patch10/Makefile     2004-11-13 15:50:49.000000000 +0000
++++ proll-patch-15/Makefile    2005-11-09 18:14:51.000000000 +0000
 @@ -4,6 +4,7 @@
        make -C krups-ser    all
        make -C espresso     all
@@ -14,14 +14,14 @@ diff -ruN proll_18.orig/Makefile proll-patch10/Makefile
        make -C espresso     clean
        make -C espresso-ser clean
 +      make -C qemu clean
-diff -ruN proll_18.orig/qemu/Makefile proll-patch10/qemu/Makefile
+diff -ruN proll_18.orig/qemu/Makefile proll-patch-15/qemu/Makefile
 --- proll_18.orig/qemu/Makefile        1970-01-01 00:00:00.000000000 +0000
-+++ proll-patch10/qemu/Makefile        2005-04-12 14:42:23.000000000 +0000
++++ proll-patch-15/qemu/Makefile       2005-08-14 10:25:06.000000000 +0000
 @@ -0,0 +1,123 @@
 +#
 +# proll:
 +# qemu/Makefile - make PROLL for QEMU
-+# $Id: proll.patch,v 1.5 2005/04/26 21:02:48 bellard Exp $
++# $Id: proll.patch,v 1.6 2005/11/11 00:24:57 bellard Exp $
 +#
 +# Copyright 1999 Pete Zaitcev
 +# This is Free Software is licensed under terms of GNU General Public License.
@@ -55,8 +55,8 @@ diff -ruN proll_18.orig/qemu/Makefile proll-patch10/qemu/Makefile
 +# Fixed %g6 is for arch/sparc/kernel/head.S, it seems ok w/o -ffixed-g6.
 +# Kernel uses -fcall-used-g5 -fcall-used-g7, we probably do not need them.
 +# __ANSI__ is supposed to be on by default but it is not.
-+CFLAGS = -O2 -Wall -DPROLBASE=$(PROLBASE) -DPROLDATA=$(PROLDATA) -DPROLRODATA=$(PROLRODATA) -D__ANSI__=1 -I$(SRC) -mcpu=hypersparc -g -DQEMU
-+ASFLAGS = -D__ASSEMBLY__ -I$(SRC) -DPROLRODATA=$(PROLRODATA) -DPROLDATA=$(PROLDATA) -DPROLSIZE=$(PROLSIZE) -g
++CFLAGS = -O2 -W -Wall -DPROLBASE=$(PROLBASE) -DPROLDATA=$(PROLDATA) -DPROLRODATA=$(PROLRODATA) -D__ANSI__=1 -I$(SRC) -mcpu=hypersparc -Wa,-xarch=v8 -g -DQEMU -m32 -fno-builtin
++ASFLAGS = -D__ASSEMBLY__ -I$(SRC) -DPROLRODATA=$(PROLRODATA) -DPROLDATA=$(PROLDATA) -DPROLSIZE=$(PROLSIZE) -g -Wa,-xarch=v8 -Wa,-32
 +# Solaris or Linux/i386 cross compilation
 +#CFLAGS = -Iinclude -O
 +
@@ -141,17 +141,17 @@ diff -ruN proll_18.orig/qemu/Makefile proll-patch10/qemu/Makefile
 +
 +proll.aout:   $(PROLLEXE)
 +      $(ELFTOAOUT) -o proll.aout $(PROLLEXE)
-diff -ruN proll_18.orig/qemu/head.S proll-patch10/qemu/head.S
+diff -ruN proll_18.orig/qemu/head.S proll-patch-15/qemu/head.S
 --- proll_18.orig/qemu/head.S  1970-01-01 00:00:00.000000000 +0000
-+++ proll-patch10/qemu/head.S  2005-03-02 15:30:47.000000000 +0000
-@@ -0,0 +1,539 @@
++++ proll-patch-15/qemu/head.S 2005-07-12 22:24:17.000000000 +0000
+@@ -0,0 +1,543 @@
 +/**
 + ** Standalone startup code for Linux PROM emulator.
 + ** Copyright 1999 Pete A. Zaitcev
 + ** This code is licensed under GNU General Public License.
 + **/
 +/*
-+ * $Id: proll.patch,v 1.5 2005/04/26 21:02:48 bellard Exp $
++ * $Id: proll.patch,v 1.6 2005/11/11 00:24:57 bellard Exp $
 + */
 +
 +#include <psr.h>
@@ -443,6 +443,10 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch10/qemu/head.S
 +C_LABEL(bootup_user_stack):           .skip 0x2000
 +
 +      .section ".text"
++      .register %g2, #scratch
++      .register %g3, #scratch
++      .register %g6, #scratch
++      .register %g7, #scratch
 +
 +goprol:
 +      ! %g1 contains end of memory
@@ -684,9 +688,9 @@ diff -ruN proll_18.orig/qemu/head.S proll-patch10/qemu/head.S
 +C_LABEL(ldb_bypass):
 +      retl
 +       lduba [%o0] ASI_M_BYPASS, %o0
-diff -ruN proll_18.orig/qemu/main.c proll-patch10/qemu/main.c
+diff -ruN proll_18.orig/qemu/main.c proll-patch-15/qemu/main.c
 --- proll_18.orig/qemu/main.c  1970-01-01 00:00:00.000000000 +0000
-+++ proll-patch10/qemu/main.c  2005-04-16 18:03:23.000000000 +0000
++++ proll-patch-15/qemu/main.c 2005-08-14 10:07:48.000000000 +0000
 @@ -0,0 +1,185 @@
 +/**
 + ** Proll (PROM replacement)
@@ -852,7 +856,7 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch10/qemu/main.c
 +
 +/*
 + */
-+void udelay(unsigned long usecs)
++void udelay(__attribute__((unused)) unsigned long usecs)
 +{
 +    // Qemu hardware is perfect and does not need any delays!
 +}
@@ -873,10 +877,10 @@ diff -ruN proll_18.orig/qemu/main.c proll-patch10/qemu/main.c
 +      hw_idprom = va_prom; 
 +}
 +
-diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
+diff -ruN proll_18.orig/qemu/openprom.c proll-patch-15/qemu/openprom.c
 --- proll_18.orig/qemu/openprom.c      1970-01-01 00:00:00.000000000 +0000
-+++ proll-patch10/qemu/openprom.c      2005-04-16 17:30:19.000000000 +0000
-@@ -0,0 +1,741 @@
++++ proll-patch-15/qemu/openprom.c     2005-11-07 20:11:04.000000000 +0000
+@@ -0,0 +1,910 @@
 +/*
 + * PROM interface support
 + * Copyright 1996 The Australian National University.
@@ -900,7 +904,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +struct property {
 +      const char *name;
 +      const char *value;
-+      const int length;
++      int length;
 +};
 +
 +struct node {
@@ -920,12 +924,13 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +static const struct property null_properties = { NULL, NULL, -1 };
 +static const int prop_true = -1;
 +
-+static const struct property propv_root[] = {
-+      {"name",        "SUNW,JavaStation-1", sizeof("SUNW,JavaStation-1") },
++static struct property propv_root[7];
++
++static const struct property propv_root_templ[] = {
++      {"name",        "SUNW,SparcStation-5", sizeof("SUNW,SparcStation-5") },
 +      {"idprom",      obp_idprom, IDPROM_SIZE},
-+      {"banner-name", "JavaStation", sizeof("JavaStation")},
++      {"banner-name", "SparcStation", sizeof("SparcStation")},
 +      {"compatible",  "sun4m", 6},
-+      {NULL, NULL, -1}
 +};
 +
 +static const int prop_iommu_reg[] = {
@@ -986,7 +991,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +static const int height = 0x300;
 +static const int width = 0x400;
 +static const int linebytes = 0x400;
-+static const int depth = 8;
++static const int depth = 24;
 +static const int tcx_intr[] = { 5, 0 };
 +static const int tcx_interrupts = 5;
 +static const struct property propv_sbus_tcx[] = {
@@ -1004,7 +1009,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +      {"linebytes",   (char*)&linebytes, sizeof(int)},
 +      {"depth",       (char*)&depth, sizeof(int)},
 +      {"reg",         (char*)&prop_tcx_regs[0], sizeof(prop_tcx_regs)},
-+      {"tcx-8-bit",   (char*)&prop_true, 0},
++      {"tcx-8-bit",   0, -1},
 +      {"intr",        (char*)&tcx_intr[0], sizeof(tcx_intr)},
 +      {"interrupts",  (char*)&tcx_interrupts, sizeof(tcx_interrupts)},
 +      {"device_type", "display", sizeof("display")},
@@ -1101,15 +1106,17 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +static const int prop_zs_reg[] = {
 +      0x0, 0x00000000, 0x00000008,
 +};
-+static const int prop_zs_slave[] = { 1 };
 +static void *prop_zs_addr;
++static const int prop_zs_slave = 1;
 +static const struct property propv_obio_zs[] = {
 +      {"name",        "zs", sizeof("zs")},
 +      {"reg",         (char*)&prop_zs_reg[0], sizeof(prop_zs_reg) },
-+      {"slave",       (char*)&prop_zs_slave[0], sizeof(prop_zs_slave) },
++      {"slave",       (char*)&prop_zs_slave, sizeof(prop_zs_slave) },
 +      {"device_type", "serial", sizeof("serial") },
 +      {"intr",        (char*)&prop_zs_intr[0], sizeof(prop_zs_intr) },
 +      {"address",     (char*)&prop_zs_addr, sizeof(prop_zs_addr) },
++      {"keyboard",    (char*)&prop_true, 0},
++      {"mouse",       (char*)&prop_true, 0},
 +      {NULL, NULL, -1}
 +};
 +
@@ -1118,11 +1125,11 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +      0x0, 0x00100000, 0x00000008,
 +};
 +static void *prop_zs1_addr;
-+static const int prop_zs1_slave[] = { 0 };
++static const int prop_zs1_slave = 0;
 +static const struct property propv_obio_zs1[] = {
 +      {"name",        "zs", sizeof("zs")},
 +      {"reg",         (char*)&prop_zs1_reg[0], sizeof(prop_zs1_reg) },
-+      {"slave",       (char*)&prop_zs1_slave[0], sizeof(prop_zs1_slave) },
++      {"slave",       (char*)&prop_zs1_slave, sizeof(prop_zs1_slave) },
 +      {"device_type", "serial", sizeof("serial") },
 +      {"intr",        (char*)&prop_zs1_intr[0], sizeof(prop_zs1_intr) },
 +      {"address",     (char*)&prop_zs1_addr, sizeof(prop_zs1_addr) },
@@ -1185,6 +1192,15 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +      {NULL, NULL, -1}
 +};
 +
++static const int prop_apc_reg[] = {
++      0x4, 0x0a000000, 0x00000010,
++};
++static const struct property propv_sbus_apc[] = {
++      {"name",        "xxxpower-management", sizeof("xxxpower-management")},
++      {"reg",         (char*)&prop_apc_reg[0], sizeof(prop_apc_reg) },
++      {NULL, NULL, -1}
++};
++
 +static const int prop_fd_intr[] = { 0x2b, 0x0 };
 +static const int prop_fd_reg[] = {
 +      0x0, 0x00400000, 0x0000000f,
@@ -1221,41 +1237,62 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +      {"name",        "options", sizeof("options")},
 +      {"screen-#columns",     "80", sizeof("80")},
 +      {"screen-#rows",        "25", sizeof("25")},
-+      {"tpe-link-test?",      "true", sizeof("true")},
++      {"tpe-link-test?",      (char *)&prop_true, 0},
 +      {"ttya-mode",           "9600,8,n,1,-", sizeof("9600,8,n,1,-")},
-+      {"ttya-ignore-cd",      "true", sizeof("true")},
-+      {"ttya-rts-dtr-off",    "false", sizeof("false")},
++      {"ttya-ignore-cd",      (char *)&prop_true, 0},
++      {"ttya-rts-dtr-off",    0, -1},
 +      {"ttyb-mode",           "9600,8,n,1,-", sizeof("9600,8,n,1,-")},
-+      {"ttyb-ignore-cd",      "true", sizeof("true")},
-+      {"ttyb-rts-dtr-off",    "false", sizeof("false")},
++      {"ttyb-ignore-cd",      (char *)&prop_true, 0},
++      {"ttyb-rts-dtr-off",    0, -1},
++      {NULL, NULL, -1}
++};
++
++static int prop_mem_reg[3];
++static int prop_mem_avail[3];
++
++static const struct property propv_memory[] = {
++      {"name",        "memory", sizeof("memory")},
++      {"reg",         (char*)&prop_mem_reg[0], sizeof(prop_mem_reg) },
++      {"available",   (char*)&prop_mem_avail[0], sizeof(prop_mem_avail) },
++      {NULL, NULL, -1}
++};
++
++static int prop_vmem_avail[6];
++
++static const struct property propv_vmemory[] = {
++      {"name",        "virtual-memory", sizeof("virtual-memory")},
++      {"available",   (char*)&prop_vmem_avail[0], sizeof(prop_vmem_avail) },
 +      {NULL, NULL, -1}
 +};
 +
 +static const struct node nodes[] = {
 +      { &null_properties,      1,  0 }, /* 0 = big brother of root */
 +      { propv_root,            0,  2 }, /*  1 "/" */
-+      { propv_iommu,          11,  3 }, /*  2 "/iommu" */
++      { propv_iommu,          12,  3 }, /*  2 "/iommu" */
 +      { propv_sbus,            0,  4 }, /*  3 "/iommu/sbus" */
 +      { propv_sbus_tcx,        5,  0 }, /*  4 "/iommu/sbus/SUNW,tcx" */
 +      { propv_sbus_ledma,      7,  6 }, /*  5 "/iommu/sbus/ledma" */
 +      { propv_sbus_ledma_le,   0,  0 }, /*  6 "/iommu/sbus/ledma/le" */
 +      { propv_sbus_cs4231,     8,  0 }, /*  7 "/iommu/sbus/SUNW,CS4231 */
 +      { propv_sbus_bpp,        9,  0 }, /*  8 "/iommu/sbus/SUNW,bpp */
-+      { propv_sbus_espdma,     0, 10 }, /*  9 "/iommu/sbus/espdma" */
++      { propv_sbus_espdma,    11, 10 }, /*  9 "/iommu/sbus/espdma" */
 +      { propv_sbus_espdma_esp, 0,  0 }, /* 10 "/iommu/sbus/espdma/esp" */
-+      { propv_cpu,            12,  0 }, /* 11 "/STP1012PGA" */
-+      { propv_obio,           22, 13 }, /* 12 "/obio" */
-+      { propv_obio_int,       14,  0 }, /* 13 "/obio/interrupt" */
-+      { propv_obio_cnt,       15,  0 }, /* 14 "/obio/counter" */
-+      { propv_obio_eep,       16,  0 }, /* 15 "/obio/eeprom" */
-+      { propv_obio_auxio,     17,  0 }, /* 16 "/obio/auxio" */
-+      { propv_obio_zs1,       18,  0 }, /* 17 "/obio/zs@0,100000"
++      { propv_sbus_apc,        0,  0 }, /* 11 "/iommu/sbus/power-management */
++      { propv_cpu,            13,  0 }, /* 12 "/STP1012PGA" */
++      { propv_obio,           23, 14 }, /* 13 "/obio" */
++      { propv_obio_int,       15,  0 }, /* 14 "/obio/interrupt" */
++      { propv_obio_cnt,       16,  0 }, /* 15 "/obio/counter" */
++      { propv_obio_eep,       17,  0 }, /* 16 "/obio/eeprom" */
++      { propv_obio_auxio,     18,  0 }, /* 17 "/obio/auxio" */
++      { propv_obio_zs1,       19,  0 }, /* 18 "/obio/zs@0,100000"
 +                                           Must be before zs@0,0! */
-+      { propv_obio_zs,        19,  0 }, /* 18 "/obio/zs@0,0" */
-+      { propv_obio_fd,        20,  0 }, /* 19 "/obio/SUNW,fdtwo" */
-+      { propv_obio_pw,        21,  0 }, /* 20 "/obio/power" */
-+      { propv_obio_cf,         0,  0 }, /* 21 "/obio/slavioconfig@0,800000" */
-+      { propv_options,         0,  0 }, /* 22 "/options" */
++      { propv_obio_zs,        20,  0 }, /* 19 "/obio/zs@0,0" */
++      { propv_obio_fd,        21,  0 }, /* 20 "/obio/SUNW,fdtwo" */
++      { propv_obio_pw,        22,  0 }, /* 21 "/obio/power" */
++      { propv_obio_cf,         0,  0 }, /* 22 "/obio/slavioconfig@0,800000" */
++      { propv_options,        24,  0 }, /* 23 "/options" */
++      { propv_memory,         25,  0 }, /* 24 "/memory" */
++      { propv_vmemory,         0,  0 }, /* 25 "/virtual-memory" */
 +};
 +
 +static struct linux_mlist_v0 totphys[MAX_BANKS];
@@ -1281,6 +1318,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +
 +static void (*synch_hook)(void);
 +static char obp_stdin, obp_stdout;
++static int obp_fd_stdin, obp_fd_stdout;
 +
 +static int obp_nbgetchar(void);
 +static int obp_nbputchar(int ch);
@@ -1289,9 +1327,13 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +static void obp_halt(void);
 +static int obp_devopen(char *str);
 +static int obp_devclose(int dev_desc);
++static int obp_devread(int dev_desc, char *buf, int nbytes);
++static int obp_devwrite(int dev_desc, char *buf, int nbytes);
++static int obp_devseek(int dev_desc, int hi, int lo);
 +static int obp_rdblkdev(int dev_desc, int num_blks, int blk_st, char *buf);
 +static char *obp_dumb_mmap(char *va, int which_io, unsigned int pa, unsigned int size);
 +static void obp_dumb_munmap(char *va, unsigned int size);
++static int obp_inst2pkg(int dev_desc);
 +
 +static void doublewalk(unsigned ptab1, unsigned va)
 +{
@@ -1304,6 +1346,17 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +
 +static struct linux_romvec romvec0;
 +
++struct fd {
++    int unit, part;
++    int offset;
++    int (*pread)(int dev_desc, int offset, char *buf, unsigned int nbytes);
++    int (*pwrite)(int dev_desc, int offset, char *buf, unsigned int nbytes);
++} fd_table[16];
++
++static int fd_index;
++static int con_pread(int dev_desc, int offset, char *buf, unsigned int nbytes);
++static int con_pwrite(int dev_desc, int offset, char *buf, unsigned int nbytes);
++
 +void *
 +init_openprom_qemu(int bankc, struct bank *bankv, unsigned hiphybas,
 +                 const char *cmdline, char boot_device, int nographic)
@@ -1345,6 +1398,18 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +      totmap[0].theres_more = 0;
 +      totmap[0].start_adr = (char*) PROLBASE;
 +      totmap[0].num_bytes = PROLSIZE;
++      prop_mem_reg[0] = 0;
++      prop_mem_reg[1] = 0;
++      prop_mem_reg[2] = bankv[0].length;
++      prop_mem_avail[0] = 0;
++      prop_mem_avail[1] = 0;
++      prop_mem_avail[2] = hiphybas;
++      prop_vmem_avail[0] = 0;
++      prop_vmem_avail[1] = 0;
++      prop_vmem_avail[2] = PROLBASE-1;
++      prop_vmem_avail[3] = 0;
++      prop_vmem_avail[4] = 0xffe00000;
++      prop_vmem_avail[5] = 0x00200000;
 +
 +      /*
 +       * idprom
@@ -1353,6 +1418,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +
 +      // Linux wants a R/W romvec table
 +      romvec0.pv_magic_cookie = LINUX_OPPROM_MAGIC;
++      romvec0.pv_romvers = 3;
 +      romvec0.pv_plugin_revision = 77;
 +      romvec0.pv_printrev = 0x10203;
 +      romvec0.pv_v0mem.v0_totphys = &ptphys;
@@ -1375,10 +1441,17 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +      romvec0.pv_halt = obp_halt;
 +      romvec0.pv_synchook = &synch_hook;
 +      romvec0.pv_v0bootargs = &obp_argp;
++      romvec0.pv_v2devops.v2_inst2pkg = obp_inst2pkg;
 +      romvec0.pv_v2devops.v2_dumb_mmap = obp_dumb_mmap;
 +      romvec0.pv_v2devops.v2_dumb_munmap = obp_dumb_munmap;
++      romvec0.pv_v2devops.v2_dev_open = obp_devopen;
++      romvec0.pv_v2devops.v2_dev_close = (void (*)(int))obp_devclose;
++      romvec0.pv_v2devops.v2_dev_read = obp_devread;
++      romvec0.pv_v2devops.v2_dev_write = obp_devwrite;
++      romvec0.pv_v2devops.v2_dev_seek = obp_devseek;
 +      obp_arg.boot_dev_ctrl = 0;
 +      obp_arg.boot_dev_unit = '0';
++      obp_arg.argv[0] = "sd(0,0,0):d";
 +      switch(boot_device) {
 +      default:
 +      case 'a':
@@ -1388,9 +1461,9 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +          break;
 +      case 'd':
 +          obp_arg.boot_dev_unit = '2';
++          obp_arg.argv[0] = "sd(0,2,0):d";
 +          // Fall through
 +      case 'c':
-+          obp_arg.argv[0] = "sd()";
 +          obp_arg.boot_dev[0] = 's';
 +          obp_arg.boot_dev[1] = 'd';
 +          break;
@@ -1401,13 +1474,39 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +          break;
 +      }
 +      obp_arg.argv[1] = cmdline;
-+
++      romvec0.pv_v2bootargs.bootpath = &obp_arg.argv[0];
++      romvec0.pv_v2bootargs.bootargs = &cmdline;
++      romvec0.pv_v2bootargs.fd_stdin = &obp_fd_stdin;
++      romvec0.pv_v2bootargs.fd_stdout = &obp_fd_stdout;
++
++      bcopy(propv_root_templ, propv_root, sizeof(propv_root_templ));
++      propv_root[4].name = "stdin-path";
++      propv_root[5].name = "stdout-path";
++      obp_fd_stdin = 0;
++      obp_fd_stdout = 1;
++      fd_table[0].pread = con_pread;
++      fd_table[0].pwrite = con_pwrite;
++      fd_table[1].pread = con_pread;
++      fd_table[1].pwrite = con_pwrite;
++      fd_index = 2;
 +      if (nographic) {
 +          obp_stdin = PROMDEV_TTYA;
++          propv_root[4].value = "/obio/zs@0,100000:a";
++          propv_root[4].length = sizeof("/obio/zs@0,100000:a");
++          fd_table[0].unit = 18;
 +          obp_stdout = PROMDEV_TTYA;
++          propv_root[5].value = "/obio/zs@0,100000:a";
++          propv_root[5].length = sizeof("/obio/zs@0,100000:a");
++          fd_table[1].unit = 18;
 +      } else {
 +          obp_stdin = PROMDEV_KBD;
++          propv_root[4].value = "/obio/zs@0,0";
++          propv_root[4].length = sizeof("/obio/zs@0,0");
++          fd_table[0].unit = 19;
 +          obp_stdout = PROMDEV_SCREEN;
++          propv_root[5].value = "/iommu/sbus/SUNW,tcx";
++          propv_root[5].length = sizeof("/iommu/sbus/SUNW,tcx");
++          fd_table[1].unit = 4;
 +      }
 +      prop_zs_addr = map_io(0x71000000, 8);
 +      prop_zs1_addr = map_io(0x71100000, 8);
@@ -1481,7 +1580,10 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +      return -1;
 +}
 +
-+static int obp_setprop(int node, char *name, char *value, int len)
++static int obp_setprop(__attribute__((unused)) int node,
++                     __attribute__((unused)) char *name,
++                     __attribute__((unused)) char *value,
++                     __attribute__((unused)) int len)
 +{
 +#ifdef DEBUG_OBP
 +        printk("obp_setprop(%d, %s) = %s (%d)\n", node, name, value, len);
@@ -1511,7 +1613,7 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +#ifdef DEBUG_OBP
 +        printk("obp_nextprop(%d, %s): not found\n", node, name);
 +#endif
-+      return (const char *)-1;
++      return "";
 +}
 +
 +extern int (*getch_fn)(struct vconterm *v);
@@ -1527,21 +1629,60 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +}
 +
 +static void obp_reboot(char *str) {
-+      printk("rebooting (%s): not implemented, freezing\n", str);
++      printk("rebooting (%s)\n", str);
++      stb_bypass(0x71f00000, 1);
 +      for (;;) {}
 +}
 +
 +static void obp_abort() {
-+      printk("abort, freezing\n");
++      printk("abort, power off\n");
++      stb_bypass(0x71910000, 1);
 +      for (;;) {}
 +}
 +
 +static void obp_halt() {
-+      printk("halt, freezing\n");
++      printk("halt, power off\n");
++      stb_bypass(0x71910000, 1);
 +      for (;;) {}
 +}
++
++extern void *esp_read(int unit, int part, int offset, short len);
++
++static int esp_pread(int dev_desc, int offset, char *buf, unsigned int nbytes)
++{
++    unsigned int i;
++    void *src;
++
++    for(i = 0; i < nbytes; i += 512) {
++      src = esp_read(fd_table[dev_desc].unit, fd_table[dev_desc].part, (offset + i) / 512, 512);
++      memcpy(&buf[i], src, 512);
++    }
++    return nbytes;
++}
++
++static int con_pread(__attribute__((unused)) int dev_desc, __attribute__((unused)) int offset, char *buf, unsigned int nbytes)
++{
++    unsigned int i;
++
++    for(i = 0; i < nbytes; i ++) {
++      buf[i] = obp_nbgetchar();
++    }
++    return nbytes;
++}
++
++static int con_pwrite(__attribute__((unused)) int dev_desc, __attribute__((unused)) int offset, char *buf, unsigned int nbytes)
++{
++    unsigned int i;
++
++    for(i = 0; i < nbytes; i ++) {
++      obp_nbputchar(buf[i]);
++    }
++    return nbytes;
++}
++
 +#define isnum(c) ((c >= '0') && (c < '9'))
 +#define ctoi(c) (c - '0')
++
 +static int obp_devopen(char *str) {
 +#ifdef DEBUG_OBP
 +        printk("obp_devopen(%s)\n", str);
@@ -1557,39 +1698,32 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +          else {
 +              target = ctoi(str[5]) & 7;
 +          }
-+          return 's' + target;
++          fd_table[fd_index].unit = target;
++          fd_table[fd_index].part = str[10] - 'a';
++          fd_table[fd_index].pread = esp_pread;
++          return fd_index++; // XXX
 +      }
 +      return 0;
 +}
 +
-+static int obp_devclose(int dev_desc) {
++static int obp_devclose(__attribute__((unused)) int dev_desc) {
 +#ifdef DEBUG_OBP
 +        printk("obp_devclose %d\n", dev_desc);
 +#endif
++      fd_index--; // XXX
 +      return 0;
 +}
 +
-+extern void *esp_read(int unit, int offset, short len);
-+
 +static int obp_rdblkdev(int dev_desc, int num_blks, int offset, char *buf)
 +{
-+    unsigned int i;
-+    void *src;
-+
 +#ifdef DEBUG_OBP
 +    printk("obp_rdblkdev: fd %d, num_blks %d, offset %d, buf 0x%x\n", dev_desc, num_blks, offset, buf);
 +#endif
-+    if (dev_desc >= 's' && dev_desc < 'v') {
-+      for(i = 0; i < num_blks; i++) {
-+          src = esp_read(dev_desc - 's', offset + i, 1);
-+          memcpy(&buf[i << 9], src, 512);
-+      }
-+      return num_blks;
-+    }
-+    return -1;
++    return fd_table[dev_desc].pread(dev_desc, offset, buf, num_blks * 512);
 +}
 +
-+static char *obp_dumb_mmap(char *va, int which_io, unsigned int pa, unsigned int size)
++static char *obp_dumb_mmap(char *va, __attribute__((unused)) int which_io,
++                         unsigned int pa, unsigned int size)
 +{
 +      unsigned int npages;
 +      unsigned int off;
@@ -1611,16 +1745,55 @@ diff -ruN proll_18.orig/qemu/openprom.c proll-patch10/qemu/openprom.c
 +      return va;
 +}
 +
-+static void obp_dumb_munmap(char *va, unsigned int size)
++static void obp_dumb_munmap(__attribute__((unused)) char *va,
++                          __attribute__((unused)) unsigned int size)
 +{
 +#ifdef DEBUG_OBP
 +      printk("obp_dumb_munmap: virta %x, sz %d\n", va, size);
 +#endif
-+    
 +}
-diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch10/qemu/system_qemu.c
++
++static int obp_devread(int dev_desc, char *buf, int nbytes)
++{
++      int ret;
++#ifdef DEBUG_OBP
++      printk("obp_devread: fd %d, nbytes %d\n", dev_desc, nbytes);
++#endif
++      ret = fd_table[dev_desc].pread(dev_desc, fd_table[dev_desc].offset, buf, nbytes);
++      fd_table[dev_desc].offset += nbytes;
++      return ret;
++}
++
++static int obp_devwrite(int dev_desc, char *buf, int nbytes)
++{
++      int ret;
++#ifdef DEBUG_OBP
++      printk("obp_devwrite: fd %d, buf %s, nbytes %d\n", dev_desc, buf, nbytes);
++#endif
++      ret = fd_table[dev_desc].pwrite(dev_desc, fd_table[dev_desc].offset, buf, nbytes);
++      fd_table[dev_desc].offset += nbytes;
++      return ret;
++}
++
++static int obp_devseek(int dev_desc, __attribute__((unused)) int hi, int lo)
++{
++#ifdef DEBUG_OBP
++      printk("obp_devseek: fd %d, hi %d, lo %d\n", dev_desc, hi, lo);
++#endif
++      fd_table[dev_desc].offset = lo;
++      return 0;
++}
++
++static int obp_inst2pkg(int dev_desc)
++{
++#ifdef DEBUG_OBP
++      printk("obp_inst2pkg: fd %d\n", dev_desc);
++#endif
++      return fd_table[dev_desc].unit;
++}
+diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch-15/qemu/system_qemu.c
 --- proll_18.orig/qemu/system_qemu.c   1970-01-01 00:00:00.000000000 +0000
-+++ proll-patch10/qemu/system_qemu.c   2005-04-16 06:16:20.000000000 +0000
++++ proll-patch-15/qemu/system_qemu.c  2005-04-16 06:16:20.000000000 +0000
 @@ -0,0 +1,430 @@
 +/**
 + ** Proll (PROM replacement)
@@ -2052,9 +2225,9 @@ diff -ruN proll_18.orig/qemu/system_qemu.c proll-patch10/qemu/system_qemu.c
 +      n = (n>>24 & 0xFF) | (n>>8 & 0xFF00) | ((n&0xFF00) << 8) | (n<<24);
 +      st_bypass(ptr, n);
 +};
-diff -ruN proll_18.orig/src/arp.c proll-patch10/src/arp.c
+diff -ruN proll_18.orig/src/arp.c proll-patch-15/src/arp.c
 --- proll_18.orig/src/arp.c    2001-12-24 05:12:31.000000000 +0000
-+++ proll-patch10/src/arp.c    2004-11-13 15:50:49.000000000 +0000
++++ proll-patch-15/src/arp.c   2005-08-14 10:10:11.000000000 +0000
 @@ -45,7 +45,7 @@
  #endif
  static struct arp_cache arp_list[ARPNUM];     /* ARP address cache    */
@@ -2064,7 +2237,19 @@ diff -ruN proll_18.orig/src/arp.c proll-patch10/src/arp.c
  
  
  
-@@ -144,7 +144,7 @@
+@@ -100,10 +100,7 @@
+  * 
+  * ARP receiver routine
+  */
+-static int arp_recv(buf, bufsize, addr)
+-unsigned char *buf;
+-int            bufsize;
+-unsigned char *addr;
++static int arp_recv(unsigned char *buf, unsigned int bufsize, unsigned char *addr)
+ {
+   register struct arphdr *ahp = (struct arphdr *)buf;
+@@ -144,7 +141,7 @@
   * 
   * Resolve IP address and return pointer to hardware address.
   */
@@ -2073,7 +2258,7 @@ diff -ruN proll_18.orig/src/arp.c proll-patch10/src/arp.c
  t_ipaddr ip;
  {
    int i;
-@@ -230,14 +230,11 @@
+@@ -230,14 +227,11 @@
   */
  int init_arp()
  {
@@ -2089,9 +2274,9 @@ diff -ruN proll_18.orig/src/arp.c proll-patch10/src/arp.c
 +  def_gw = IP_ANY;
    return(TRUE);
  }
-diff -ruN proll_18.orig/src/arp.h proll-patch10/src/arp.h
+diff -ruN proll_18.orig/src/arp.h proll-patch-15/src/arp.h
 --- proll_18.orig/src/arp.h    1999-03-18 03:39:43.000000000 +0000
-+++ proll-patch10/src/arp.h    2004-11-13 15:50:49.000000000 +0000
++++ proll-patch-15/src/arp.h   2004-11-13 15:50:49.000000000 +0000
 @@ -104,7 +104,7 @@
  extern int init_arp __P((void));
  
@@ -2101,10 +2286,22 @@ diff -ruN proll_18.orig/src/arp.h proll-patch10/src/arp.h
  
  /* Add a new antry to the ARP cache */
  extern void addcache __P((unsigned char *ha, t_ipaddr ip));
-diff -ruN proll_18.orig/src/esp.c proll-patch10/src/esp.c
+diff -ruN proll_18.orig/src/bootp.c proll-patch-15/src/bootp.c
+--- proll_18.orig/src/bootp.c  1999-12-15 17:20:30.000000000 +0000
++++ proll-patch-15/src/bootp.c 2005-08-14 10:16:09.000000000 +0000
+@@ -151,7 +151,7 @@
+   while (TRUE) {
+       boot_xid = get_ticks() + random();
+       bootp_send();
+-      i = udp_read((char *)(&boot_rec), BOOTP_REC_SIZE, timeout, CHR_ESC);
++      i = udp_read((char *)(&boot_rec), BOOTP_REC_SIZE, timeout);
+       if (i < 0) {                            /* user pressed ESC */
+               printf("\nAborted\n");
+               return(1);
+diff -ruN proll_18.orig/src/esp.c proll-patch-15/src/esp.c
 --- proll_18.orig/src/esp.c    1970-01-01 00:00:00.000000000 +0000
-+++ proll-patch10/src/esp.c    2005-04-16 06:24:23.000000000 +0000
-@@ -0,0 +1,252 @@
++++ proll-patch-15/src/esp.c   2005-08-15 18:42:46.000000000 +0000
+@@ -0,0 +1,305 @@
 +#include <system.h>           /* == <asm/system.h> */
 +#include <general.h>          /* __P for netpriv.h */
 +#include <dma.h>              /* dmaga */
@@ -2138,6 +2335,10 @@ diff -ruN proll_18.orig/src/esp.c proll-patch10/src/esp.c
 +      struct esp_dma *espdma;         /* If set this points to espdma    */
 +
 +        unsigned char *buffer;
++      struct disk_info {
++              unsigned int hw_sector;
++              unsigned int part_offset[8];
++      } disk[8];
 +};
 +
 +static void esp_interrupt(void *dev_id)
@@ -2260,7 +2461,7 @@ diff -ruN proll_18.orig/src/esp.c proll-patch10/src/esp.c
 +      return;
 +}
 +
-+void *esp_read(int unit, int offset, short len)
++void esp_read_capacity(int unit)
 +{
 +      // Set SCSI target
 +      stb_bypass(PHYS_JJ_ESP + 4*4, unit & 7);
@@ -2271,28 +2472,74 @@ diff -ruN proll_18.orig/src/esp.c proll-patch10/src/esp.c
 +      stb_bypass(PHYS_JJ_ESP + 1*4, 0);
 +      // Set DMA direction
 +      st_bypass(PHYS_JJ_ESPDMA + 0, 0x000);
++      // Setup command = Read Capacity
++      esp.buffer[0] = 0x80;
++      esp.buffer[1] = 0x25;
++      esp.buffer[2] = 0x00;
++      esp.buffer[3] = 0x00;
++      esp.buffer[4] = 0x00;
++      esp.buffer[5] = 0x00;
++      esp.buffer[6] = 0x00;
++      esp.buffer[7] = 0x00;
++      esp.buffer[8] = 0x00;
++      esp.buffer[9] = 0x00;
++      esp.buffer[10] = 0x00;
++      // Set ATN, issue command
++      stb_bypass(PHYS_JJ_ESP + 3*4, 0xc2);
++
++      // Set DMA length = 512 * read length
++      stb_bypass(PHYS_JJ_ESP + 0*4, 0);
++      stb_bypass(PHYS_JJ_ESP + 1*4, 8 & 0xff);
++      // Set DMA direction
++      st_bypass(PHYS_JJ_ESPDMA + 0, 0x100);
++      // Transfer
++      stb_bypass(PHYS_JJ_ESP + 3*4, 0x90);
++      esp.disk[unit].hw_sector = (esp.buffer[4] << 24) | (esp.buffer[5] << 16) | (esp.buffer[6] << 8) | esp.buffer[7];
++}
++
++// offset is multiple of 512, len in bytes
++void *esp_read(int unit, int part, int offset, short len)
++{
++      int pos, hw_sect, sect_offset, spb;
++
++      // Set SCSI target
++      stb_bypass(PHYS_JJ_ESP + 4*4, unit & 7);
++      // Set DMA address
++      st_bypass(PHYS_JJ_ESPDMA + 4, esp.buffer_dvma);
++      // Set DMA length
++      stb_bypass(PHYS_JJ_ESP + 0*4, 10);
++      stb_bypass(PHYS_JJ_ESP + 1*4, 0);
++      // Set DMA direction
++      st_bypass(PHYS_JJ_ESPDMA + 0, 0x000);
++      hw_sect = esp.disk[unit].hw_sector;
++      offset += esp.disk[unit].part_offset[part];
++      spb = hw_sect / 512;
++      sect_offset = offset / spb;
++      pos = (offset - sect_offset * spb) * 512;
++      len /= 512;
++      //printk("Read unit %d, offset %d -> offset %d, pos %d, hw_sect %d\n", unit, offset, sect_offset, pos, hw_sect);
 +      // Setup command = Read(10)
 +      esp.buffer[0] = 0x80;
 +      esp.buffer[1] = 0x28;
 +      esp.buffer[2] = 0x00;
-+      esp.buffer[3] = (offset >> 24) & 0xff;
-+      esp.buffer[4] = (offset >> 16) & 0xff;
-+      esp.buffer[5] = (offset >> 8) & 0xff;
-+      esp.buffer[6] = offset & 0xff;
++      esp.buffer[3] = (sect_offset >> 24) & 0xff;
++      esp.buffer[4] = (sect_offset >> 16) & 0xff;
++      esp.buffer[5] = (sect_offset >> 8) & 0xff;
++      esp.buffer[6] = sect_offset & 0xff;
 +      esp.buffer[7] = 0x00;
 +      esp.buffer[8] = (len >> 8) & 0xff;
 +      esp.buffer[9] = len & 0xff;
 +      // Set ATN, issue command
-+      stb_bypass(PHYS_JJ_ESP + 3*4, 0x42);
++      stb_bypass(PHYS_JJ_ESP + 3*4, 0xc2);
 +
-+      // Set DMA length = 512 * read length
-+      stb_bypass(PHYS_JJ_ESP + 0*4, 0);
-+      stb_bypass(PHYS_JJ_ESP + 1*4, (len << 1) & 0xff);
++      // Set DMA length = sector size * read length
++      stb_bypass(PHYS_JJ_ESP + 0*4, (len * hw_sect) & 0xff);
++      stb_bypass(PHYS_JJ_ESP + 1*4, ((len * hw_sect) >> 8) & 0xff);
 +      // Set DMA direction
 +      st_bypass(PHYS_JJ_ESPDMA + 0, 0x100);
 +      // Transfer
-+      stb_bypass(PHYS_JJ_ESP + 3*4, 0x10);
-+      return esp.buffer;
++      stb_bypass(PHYS_JJ_ESP + 3*4, 0x90);
++      return esp.buffer + pos;
 +}
 +
 +// Sparc boot sequence can be found in SILO docs,
@@ -2334,32 +2581,35 @@ diff -ruN proll_18.orig/src/esp.c proll-patch10/src/esp.c
 +      stb_bypass(PHYS_JJ_ESP + 3*4, 2);
 +
 +      esp_open(&esp);
++      esp_read_capacity(unit);
 +
-+      label = esp_read(unit, 0, 1);
-+      printk("CHS: %d/%d/%d, partitions:\n", label->ncyl, label->ntrks, label->nsect);
++      label = esp_read(unit, 0, 0, 512);
++      printk("hw sector: %d, CHS: %d/%d/%d, partitions:\n", esp.disk[unit].hw_sector, 
++             label->ncyl, label->ntrks, label->nsect);
 +      for (i = 0; i < 8; i++) {
-+          printk("%c: %d + %d\n", 'a' + i, label->partitions[i].start_cylinder,
-+                 label->partitions[i].num_sectors);
++          printk("%c: %d + %d, id %x, flags %x\n", 'a' + i, label->partitions[i].start_cylinder,
++                 label->partitions[i].num_sectors, label->infos[i].id, label->infos[i].flags);
++          esp.disk[unit].part_offset[i] = label->partitions[3].start_cylinder * label->ntrks * label->nsect;
 +      }
-+      offset = label->partitions[4].start_cylinder * label->ntrks * label->nsect + 1;
++      offset = 1;
 +      printk("booting sd(0,%d,0):d (offset %d)\n", unit, offset);
 +      // Skip a.out header (0x20)
 +      dst = (void *)0x4000;
-+      src = esp_read(unit, offset, 1);
++      src = esp_read(unit, 3, offset, 512);
 +      src = (void *)((unsigned int) src + 0x20);
 +      memcpy(dst, src, 512 - 0x20);
 +      dst = (void *)0x4000 + 512 - 0x20;
 +      for (i = 1; i < 7680/512; i++) {
-+          src = esp_read(unit, offset + i, 1);
++          src = esp_read(unit, 3,  offset + i, 512);
 +          memcpy(dst, src, 512);
 +          dst += 512;
 +      }
 +      esp_close(&esp);
 +      return 0;
 +}
-diff -ruN proll_18.orig/src/hconsole.c proll-patch10/src/hconsole.c
+diff -ruN proll_18.orig/src/hconsole.c proll-patch-15/src/hconsole.c
 --- proll_18.orig/src/hconsole.c       2002-07-23 05:52:48.000000000 +0000
-+++ proll-patch10/src/hconsole.c       2005-03-02 17:03:09.000000000 +0000
++++ proll-patch-15/src/hconsole.c      2005-11-09 18:46:34.000000000 +0000
 @@ -29,6 +29,10 @@
         struct raster r_master;        /* For a case of resize, whole fb */
         struct raster r_0;     /* malloc() erzatz */
@@ -2383,9 +2633,84 @@ diff -ruN proll_18.orig/src/hconsole.c proll-patch10/src/hconsole.c
        t->r_ = r;
        t->r0_ = q;
        t->f_ = &f_master;
-diff -ruN proll_18.orig/src/hme.c proll-patch10/src/hme.c
+@@ -67,7 +75,7 @@
+       return 0;
+ }
+-void hcon_fini (struct hconsole *t)
++void hcon_fini (__attribute((unused)) struct hconsole *t)
+ {
+       return;
+ }
+@@ -77,12 +85,12 @@
+ {
+       struct rfont *f = t->f_;
+-      if (sy < 0 || sy >= t->ydim_) return -1;
+-      if (sx < 0 || sx >= t->xdim_) return -1;
++      if (sy < 0 || (unsigned)sy >= t->ydim_) return -1;
++      if (sx < 0 || (unsigned)sx >= t->xdim_) return -1;
+       if (height < 0) return -1;
+-      if (sy + height > t->ydim_) height = t->ydim_ - sy;
++      if ((unsigned)sy + (unsigned)height > t->ydim_) height = t->ydim_ - sy;
+       if (width < 0) return -1;
+-      if (sx + width > t->xdim_) width = t->xdim_ - sx;
++      if ((unsigned)sx + (unsigned)width > t->xdim_) width = t->xdim_ - sx;
+       /* XXX Clear with correct background color */
+       (*t->r_->clear_)(t->r_,
+@@ -107,10 +115,10 @@
+       char c0 = c;
+       RC_color rfg, rbg;
+-      if (y < 0 || y >= t->ydim_) return -1;
+-      if (x < 0 || x >= t->xdim_) return -1;
++      if (y < 0 || (unsigned)y >= t->ydim_) return -1;
++      if (x < 0 || (unsigned)x >= t->xdim_) return -1;
+-      if (t->curson_ && t->ypos_ == y && t->xpos_ == x) {
++      if (t->curson_ && t->ypos_ == (unsigned)y && t->xpos_ == (unsigned)x) {
+               rfg = t->bg_;    rbg = t->fg_;
+       } else {
+               rfg = t->fg_;    rbg = t->bg_;
+@@ -126,9 +134,9 @@
+ {     
+       struct rfont *f = t->f_;
+-      if (y < 0 || y >= t->ydim_) return -1;
+-      if (x < 0 || x >= t->xdim_) return -1;
+-      if (x + count >= t->xdim_) count = t->xdim_ - x;
++      if (y < 0 || (unsigned)y >= t->ydim_) return -1;
++      if (x < 0 || (unsigned)x >= t->xdim_) return -1;
++      if ((unsigned)x + (unsigned)count >= t->xdim_) count = t->xdim_ - x;
+       (*t->r_->render_)(t->r_, y*f->height_, x*f->width_,
+                           s, count, t->bg_, t->fg_, f);
+@@ -200,8 +208,8 @@
+       rc = 0;
+       if (dir == SM_UP) {
+-              if (d < 0 || d >= t->ydim_) return -1;
+-              if (b <= d || b > t->ydim_) return -1;
++              if (d < 0 || (unsigned)d >= t->ydim_) return -1;
++              if (b <= d || (unsigned)b > t->ydim_) return -1;
+               if (d + count >= b) count = b - d;
+               if (d + count >= b) count = b - d;
+               (*t->r_->yscroll_)(t->r_,
+@@ -213,8 +221,8 @@
+                                  count*f->height_, raster_qwidth(t->r_),
+                                  t->bg_);
+       } else if (dir == SM_DOWN) {
+-              if (d < 0 || d >= t->ydim_) return -1;
+-              if (b <= d || b > t->ydim_) return -1;
++              if (d < 0 || (unsigned)d >= t->ydim_) return -1;
++              if (b <= d || (unsigned)b > t->ydim_) return -1;
+               if (d + count >= b) count = b - d;
+               (*t->r_->yscroll_)(t->r_,
+                                    d*f->height_, 0,
+diff -ruN proll_18.orig/src/hme.c proll-patch-15/src/hme.c
 --- proll_18.orig/src/hme.c    2002-07-23 05:52:52.000000000 +0000
-+++ proll-patch10/src/hme.c    2005-04-16 06:16:20.000000000 +0000
++++ proll-patch-15/src/hme.c   2005-04-16 06:16:20.000000000 +0000
 @@ -655,10 +655,10 @@
                                    unsigned int flags,
                                    unsigned int addr)
@@ -2443,9 +2768,21 @@ diff -ruN proll_18.orig/src/hme.c proll-patch10/src/hme.c
                                     : "=r" (flags)
                                     : "r" (&this->rx_flags), "i" (ASI_PL));
  #else
-diff -ruN proll_18.orig/src/lat7_2.bm proll-patch10/src/lat7_2.bm
+diff -ruN proll_18.orig/src/iommu.c proll-patch-15/src/iommu.c
+--- proll_18.orig/src/iommu.c  2002-07-23 05:52:49.000000000 +0000
++++ proll-patch-15/src/iommu.c 2005-08-14 10:08:17.000000000 +0000
+@@ -36,7 +36,7 @@
+       unsigned int pa, ba;
+       unsigned int npages;
+       unsigned int mva, mpa;
+-      int i;
++      unsigned int i;
+       unsigned int *iopte;
+       npages = (size + (PAGE_SIZE-1)) / PAGE_SIZE;
+diff -ruN proll_18.orig/src/lat7_2.bm proll-patch-15/src/lat7_2.bm
 --- proll_18.orig/src/lat7_2.bm        1999-02-27 05:48:54.000000000 +0000
-+++ proll-patch10/src/lat7_2.bm        2004-11-13 15:50:49.000000000 +0000
++++ proll-patch-15/src/lat7_2.bm       2004-11-13 15:50:49.000000000 +0000
 @@ -1,6 +1,6 @@
  #define lat7_2_width 128
  #define lat7_2_height 88
@@ -2454,9 +2791,9 @@ diff -ruN proll_18.orig/src/lat7_2.bm proll-patch10/src/lat7_2.bm
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x12, 0x1e, 0x0c, 0x02, 0x70, 0x18,
     0x22, 0x22, 0x18, 0x00, 0x00, 0x18, 0x18, 0xff, 0x18, 0x00, 0x12, 0x02,
-diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch10/src/lat7_2_swapped.bm
+diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch-15/src/lat7_2_swapped.bm
 --- proll_18.orig/src/lat7_2_swapped.bm        1970-01-01 00:00:00.000000000 +0000
-+++ proll-patch10/src/lat7_2_swapped.bm        2004-11-13 15:50:49.000000000 +0000
++++ proll-patch-15/src/lat7_2_swapped.bm       2004-11-13 15:50:49.000000000 +0000
 @@ -0,0 +1,121 @@
 +#define lat7_2_width 128
 +#define lat7_2_height 88
@@ -2579,9 +2916,9 @@ diff -ruN proll_18.orig/src/lat7_2_swapped.bm proll-patch10/src/lat7_2_swapped.b
 +   0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0x00, 0x00, 0x00, 
 +   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x42, 0x00, 0x00, 0x00, 0x00, 
 +   0x00, 0x00, 0x00, 0x00};
-diff -ruN proll_18.orig/src/le.c proll-patch10/src/le.c
+diff -ruN proll_18.orig/src/le.c proll-patch-15/src/le.c
 --- proll_18.orig/src/le.c     2002-07-23 05:52:49.000000000 +0000
-+++ proll-patch10/src/le.c     2005-04-16 06:16:20.000000000 +0000
++++ proll-patch-15/src/le.c    2005-04-16 06:16:20.000000000 +0000
 @@ -185,8 +185,6 @@
        unsigned short rap;                     /* register address port */
  };
@@ -2600,9 +2937,21 @@ diff -ruN proll_18.orig/src/le.c proll-patch10/src/le.c
      
        /* Now, give the packet to the lance */
        ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
-diff -ruN proll_18.orig/src/netinit.c proll-patch10/src/netinit.c
+diff -ruN proll_18.orig/src/net.h proll-patch-15/src/net.h
+--- proll_18.orig/src/net.h    1999-12-15 17:20:17.000000000 +0000
++++ proll-patch-15/src/net.h   2005-08-14 10:17:02.000000000 +0000
+@@ -124,7 +124,7 @@
+ extern int udp_open __P((t_ipaddr daddr, int source, int dest));
+ /* Read from a UDP socket */
+-extern int udp_read __P((char *buf, int bufsize, int timeout, char abortch));
++extern int udp_read(char *buf, unsigned int bufsize, int timeout);
+ /* Write to a UDP socket */
+ extern int udp_write __P((char *buf, int writelen));
+diff -ruN proll_18.orig/src/netinit.c proll-patch-15/src/netinit.c
 --- proll_18.orig/src/netinit.c        2002-09-13 21:53:33.000000000 +0000
-+++ proll-patch10/src/netinit.c        2004-11-13 15:50:49.000000000 +0000
++++ proll-patch-15/src/netinit.c       2004-11-13 15:50:49.000000000 +0000
 @@ -49,13 +49,20 @@
  unsigned char     myhwaddr[ETH_ALEN];         /* my own hardware addr */
           t_ipaddr myipaddr;                   /* my own IP address    */
@@ -2646,9 +2995,18 @@ diff -ruN proll_18.orig/src/netinit.c proll-patch10/src/netinit.c
        fatal();
    }
  }
-diff -ruN proll_18.orig/src/netpriv.h proll-patch10/src/netpriv.h
+diff -ruN proll_18.orig/src/netpriv.h proll-patch-15/src/netpriv.h
 --- proll_18.orig/src/netpriv.h        1999-04-27 05:39:37.000000000 +0000
-+++ proll-patch10/src/netpriv.h        2004-11-13 15:50:49.000000000 +0000
++++ proll-patch-15/src/netpriv.h       2005-08-14 10:12:20.000000000 +0000
+@@ -83,7 +83,7 @@
+        */
+       struct device *dev;
+       char *data;
+-      int len;
++      unsigned int len;
+       int protocol;
+       unsigned char ip_summed;
+ };
 @@ -130,10 +130,9 @@
   *
   */
@@ -2670,10 +3028,10 @@ diff -ruN proll_18.orig/src/netpriv.h proll-patch10/src/netpriv.h
  
  /* Empty read buffer */
  extern void empty_buf __P((void));
-diff -ruN proll_18.orig/src/openprom.h proll-patch10/src/openprom.h
+diff -ruN proll_18.orig/src/openprom.h proll-patch-15/src/openprom.h
 --- proll_18.orig/src/openprom.h       2002-07-14 02:26:30.000000000 +0000
-+++ proll-patch10/src/openprom.h       2004-11-13 15:50:49.000000000 +0000
-@@ -54,20 +54,20 @@
++++ proll-patch-15/src/openprom.h      2005-05-13 16:23:14.000000000 +0000
+@@ -54,29 +54,29 @@
  };
  
  struct linux_mem_v0 {
@@ -2699,6 +3057,19 @@ diff -ruN proll_18.orig/src/openprom.h proll-patch10/src/openprom.h
        void *aieee1;           /* XXX */
  };
  
+ /* V2 and up boot things. */
+ struct linux_bootargs_v2 {
+-      char **bootpath;
+-      char **bootargs;
+-      int *fd_stdin;
+-      int *fd_stdout;
++      const char **bootpath;
++      const char **bootargs;
++      const int *fd_stdin;
++      const int *fd_stdout;
+ };
+ /* The top level PROM vector. */
 @@ -91,13 +91,13 @@
        struct linux_mem_v0 pv_v0mem;
  
@@ -2734,9 +3105,9 @@ diff -ruN proll_18.orig/src/openprom.h proll-patch10/src/openprom.h
  };
  
  /* More fun PROM structures for device probing. */
-diff -ruN proll_18.orig/src/packet.c proll-patch10/src/packet.c
+diff -ruN proll_18.orig/src/packet.c proll-patch-15/src/packet.c
 --- proll_18.orig/src/packet.c 2000-02-11 04:56:45.000000000 +0000
-+++ proll-patch10/src/packet.c 2004-11-13 15:50:49.000000000 +0000
++++ proll-patch-15/src/packet.c        2005-08-14 10:12:49.000000000 +0000
 @@ -41,7 +41,7 @@
        int aligner;
  } wbuf;
@@ -2764,9 +3135,24 @@ diff -ruN proll_18.orig/src/packet.c proll-patch10/src/packet.c
  {
        struct sk_buff *skb;
        unsigned char *s;
-diff -ruN proll_18.orig/src/printf.c proll-patch10/src/printf.c
+@@ -209,12 +211,12 @@
+ /*
+  */
+ void
+-eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int len, int base)
++eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int len, __attribute__((unused)) int base)
+ {
+       bcopy(src, dest->data, len);
+ }
+-unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev)
++unsigned short eth_type_trans(struct sk_buff *skb, __attribute__((unused)) struct device *dev)
+ {
+       unsigned char *s = skb->data + 12;
+       return s[0] << 8 | s[1];                /* Network order word */
+diff -ruN proll_18.orig/src/printf.c proll-patch-15/src/printf.c
 --- proll_18.orig/src/printf.c 1999-03-19 07:03:59.000000000 +0000
-+++ proll-patch10/src/printf.c 2004-11-13 15:50:49.000000000 +0000
++++ proll-patch-15/src/printf.c        2005-08-14 10:07:26.000000000 +0000
 @@ -19,7 +19,7 @@
  static void printn(struct prf_fp *, unsigned long, unsigned int);
  static void putchar(char, struct prf_fp *);
@@ -2794,9 +3180,20 @@ diff -ruN proll_18.orig/src/printf.c proll-patch10/src/printf.c
                                putchar(c,filog);
                        } else if (c == 'l' || c == 'O') {
                        printn(filog, (long)va_arg(adx,long), c=='l'?10:8);
-diff -ruN proll_18.orig/src/rconsole.c proll-patch10/src/rconsole.c
+@@ -77,10 +77,6 @@
+         char prbuf[24];
+         register char *cp;
+-        if (b == 10 && n < 0) {
+-                putchar('-',filog);
+-                n = (~n) + 1;         /* n = -n */
+-        }
+         cp = prbuf;
+         do
+               *cp++ = hextab[(unsigned int)(n%b)];
+diff -ruN proll_18.orig/src/rconsole.c proll-patch-15/src/rconsole.c
 --- proll_18.orig/src/rconsole.c       1999-01-16 07:16:55.000000000 +0000
-+++ proll-patch10/src/rconsole.c       2005-04-16 06:16:20.000000000 +0000
++++ proll-patch-15/src/rconsole.c      2005-08-14 10:25:53.000000000 +0000
 @@ -28,12 +28,18 @@
   * move to California. Only plain lat7 survived. 
   * I recreated lat7-1 changes in lat7-2.  --zaitcev
@@ -2882,9 +3279,18 @@ diff -ruN proll_18.orig/src/rconsole.c proll-patch10/src/rconsole.c
    p->nchars_ = LAT7_NCHARS;
    p->width_ = LAT7_WIDTH;
    p->height_ = LAT7_HEIGHT;
-diff -ruN proll_18.orig/src/rconsole.h proll-patch10/src/rconsole.h
+@@ -175,7 +188,7 @@
+   r->render_ = p->render_;
+ }
+-void raster_dest(struct raster *r)
++void raster_dest(__attribute((unused)) struct raster *r)
+ {
+ }
+diff -ruN proll_18.orig/src/rconsole.h proll-patch-15/src/rconsole.h
 --- proll_18.orig/src/rconsole.h       1999-01-16 05:00:59.000000000 +0000
-+++ proll-patch10/src/rconsole.h       2004-11-13 15:50:49.000000000 +0000
++++ proll-patch-15/src/rconsole.h      2004-11-13 15:50:49.000000000 +0000
 @@ -13,10 +13,10 @@
   */
  
@@ -2898,9 +3304,9 @@ diff -ruN proll_18.orig/src/rconsole.h proll-patch10/src/rconsole.h
    int nchars_;                 /* 128 for ASCII ...  65536 for Unicode   */
    int width_;                  /* [Pixels]. Maximum size is 16.          */
    int height_;                 /* [Pixels == scan lines].                */
-diff -ruN proll_18.orig/src/romlib.h proll-patch10/src/romlib.h
+diff -ruN proll_18.orig/src/romlib.h proll-patch-15/src/romlib.h
 --- proll_18.orig/src/romlib.h 1999-04-20 04:26:45.000000000 +0000
-+++ proll-patch10/src/romlib.h 2005-04-16 20:32:49.000000000 +0000
++++ proll-patch-15/src/romlib.h        2005-04-16 20:32:49.000000000 +0000
 @@ -72,13 +72,13 @@
   */
  #define memcpy(dst, src, len) bcopy(src, dst, len)
@@ -2920,9 +3326,9 @@ diff -ruN proll_18.orig/src/romlib.h proll-patch10/src/romlib.h
  
  
  /*
-diff -ruN proll_18.orig/src/sched_4m.c proll-patch10/src/sched_4m.c
+diff -ruN proll_18.orig/src/sched_4m.c proll-patch-15/src/sched_4m.c
 --- proll_18.orig/src/sched_4m.c       1999-04-27 05:48:51.000000000 +0000
-+++ proll-patch10/src/sched_4m.c       2004-11-13 15:50:49.000000000 +0000
++++ proll-patch-15/src/sched_4m.c      2005-08-14 10:18:14.000000000 +0000
 @@ -108,7 +108,7 @@
  static int set_bolt;                  /* Tick counter limit */
  static struct handsc hndv[16];
@@ -2932,9 +3338,36 @@ diff -ruN proll_18.orig/src/sched_4m.c proll-patch10/src/sched_4m.c
        0,      0,      0,      0,      0,      0, SUN4M_INT_ETHERNET,  0,
        0,      0,      0,      0,      0,      0,      0,      0,
  };
-diff -ruN proll_18.orig/src/swap.c proll-patch10/src/swap.c
+@@ -130,7 +130,7 @@
+ int   /* 0 - not expired yet; <>0 - timer expired */
+ chk_timeout()
+ {
+-      int lim = (((1000000/HZ) + 1) << 10);
++      unsigned int lim = (((1000000/HZ) + 1) << 10);
+       unsigned int clear;
+       unsigned int intc;
+       int n;
+@@ -182,7 +182,7 @@
+       struct handsc *hndp;
+       unsigned int mask;
+-      if (irq < 0 || irq >= 16) {
++      if (irq == 0 || irq >= 16) {
+               printk("request_irq: bad irq %d\n", irq);
+               return -1;
+       }
+@@ -207,7 +207,7 @@
+ {
+       struct handsc *hndp;
+-      if (irq < 0 || irq >= 16) {
++      if (irq == 0 || irq >= 16) {
+               printk("free_irq: bad irq %d\n", irq);
+               return;
+       }
+diff -ruN proll_18.orig/src/swap.c proll-patch-15/src/swap.c
 --- proll_18.orig/src/swap.c   1970-01-01 00:00:00.000000000 +0000
-+++ proll-patch10/src/swap.c   2004-11-13 15:50:49.000000000 +0000
++++ proll-patch-15/src/swap.c  2004-11-13 15:50:49.000000000 +0000
 @@ -0,0 +1,21 @@
 +// Convert the lat7 font so that no conversion is needed at runtime.
 +#define ORIG
@@ -2957,9 +3390,9 @@ diff -ruN proll_18.orig/src/swap.c proll-patch10/src/swap.c
 +    }
 +    printf("\n");
 +}
-diff -ruN proll_18.orig/src/system.c proll-patch10/src/system.c
+diff -ruN proll_18.orig/src/system.c proll-patch-15/src/system.c
 --- proll_18.orig/src/system.c 2002-07-23 05:52:49.000000000 +0000
-+++ proll-patch10/src/system.c 2005-04-16 06:16:20.000000000 +0000
++++ proll-patch-15/src/system.c        2005-04-16 06:16:20.000000000 +0000
 @@ -298,8 +298,8 @@
        }
  
@@ -3050,9 +3483,9 @@ diff -ruN proll_18.orig/src/system.c proll-patch10/src/system.c
  void fatal()
  {
        printk("fatal.");
-diff -ruN proll_18.orig/src/system.h proll-patch10/src/system.h
+diff -ruN proll_18.orig/src/system.h proll-patch-15/src/system.h
 --- proll_18.orig/src/system.h 2002-09-13 21:53:32.000000000 +0000
-+++ proll-patch10/src/system.h 2005-04-16 06:16:20.000000000 +0000
++++ proll-patch-15/src/system.h        2005-04-16 06:16:20.000000000 +0000
 @@ -16,7 +16,7 @@
  #define IOMAPSIZE (1*1024*1024) /* 1 Meg maximum: we do not map framebuffer. */
  #define NCTX_SWIFT  0x100
@@ -3171,19 +3604,72 @@ diff -ruN proll_18.orig/src/system.h proll-patch10/src/system.h
                : "i" (PSR_PIL)
                : "g1", "memory");
  
-diff -ruN proll_18.orig/src/udp.c proll-patch10/src/udp.c
+diff -ruN proll_18.orig/src/tftp.c proll-patch-15/src/tftp.c
+--- proll_18.orig/src/tftp.c   2002-09-13 21:53:34.000000000 +0000
++++ proll-patch-15/src/tftp.c  2005-08-14 10:16:15.000000000 +0000
+@@ -127,7 +127,7 @@
+   int len;
+   /* Read packet with timeout */
+-  len = udp_read((char *)(&inpbuf), sizeof(inpbuf), TFTP_TIMEOUT, CHR_ESC);
++  len = udp_read((char *)(&inpbuf), sizeof(inpbuf), TFTP_TIMEOUT);
+   if (len == 0) {
+       printf("TFTP: Timeout\n");
+       return(ERR_TIMEOUT);
+diff -ruN proll_18.orig/src/udp.c proll-patch-15/src/udp.c
 --- proll_18.orig/src/udp.c    2001-12-24 05:12:53.000000000 +0000
-+++ proll-patch10/src/udp.c    2004-11-13 15:50:49.000000000 +0000
-@@ -81,7 +81,7 @@
- int      source;
- int      dest;
++++ proll-patch-15/src/udp.c   2005-08-14 10:17:19.000000000 +0000
+@@ -76,12 +76,9 @@
+  * 
+  * Open a new UDP socket.
+  */
+-int udp_open(daddr, source, dest)
+-t_ipaddr daddr;
+-int      source;
+-int      dest;
++int udp_open(t_ipaddr daddr, int source, int dest)
  {
 -  register unsigned char *addr;
-+  const register unsigned char *addr;
++  const unsigned char *addr;
  
    /* Set global variables */
    usource = source;
-@@ -299,9 +299,6 @@
+@@ -101,16 +98,13 @@
+  * 
+  * IP receiver routine
+  */
+-static int ip_recv(buf, bufsize, addr)
+-unsigned char *buf;
+-int            bufsize;
+-unsigned char *addr;
++static int ip_recv(unsigned char *buf, unsigned int bufsize, unsigned char *addr)
+ {
+   struct iphdr *ipp = ((struct iphdr *)buf);
+   struct udphdr *udpp = ((struct udphdr *)(buf + IP_MIN_HSIZE));
+   struct udp_pseudo psehdr;
+-  int size;
++  unsigned int size;
+   t_ipaddr dadr;
+ #ifdef DEBUG
+@@ -194,13 +188,9 @@
+  * 
+  * Read one packet from a UDP socket
+  */
+-int udp_read(buf, bufsize, timeout, abortch)
+-char *buf;
+-int   bufsize;
+-int   timeout;
+-char  abortch;
++int udp_read(char *buf, unsigned int bufsize, int timeout)
+ {
+-  int len;
++  unsigned int len;
+   /* Wait until we get something */
+   set_timeout(timeout);
+@@ -299,9 +289,6 @@
   */
  int init_udp()
  {
@@ -3193,9 +3679,21 @@ diff -ruN proll_18.orig/src/udp.c proll-patch10/src/udp.c
    /* Register IP packet type and set write buffer pointer */
    if ((writebuf = reg_type(htons(ETH_P_IP), ip_recv)) == NULL)
        return(FALSE);
-diff -ruN proll_18.orig/src/vcons_zs.c proll-patch10/src/vcons_zs.c
+diff -ruN proll_18.orig/src/udp.h proll-patch-15/src/udp.h
+--- proll_18.orig/src/udp.h    2001-12-24 05:12:34.000000000 +0000
++++ proll-patch-15/src/udp.h   2005-08-14 10:16:40.000000000 +0000
+@@ -53,7 +53,7 @@
+ extern int udp_open __P((t_ipaddr daddr, int source, int dest));
+ /* Read from a UDP socket */
+-extern int udp_read __P((char *buf, int bufsize, int timeout, char abortch));
++extern int udp_read(char *buf, unsigned int bufsize, int timeout);
+ /* Write to a UDP socket */
+ extern int udp_write __P((char *buf, int writelen));
+diff -ruN proll_18.orig/src/vcons_zs.c proll-patch-15/src/vcons_zs.c
 --- proll_18.orig/src/vcons_zs.c       1970-01-01 00:00:00.000000000 +0000
-+++ proll-patch10/src/vcons_zs.c       2005-04-10 07:01:03.000000000 +0000
++++ proll-patch-15/src/vcons_zs.c      2005-08-14 10:25:51.000000000 +0000
 @@ -0,0 +1,68 @@
 +/**
 + ** Console over 'zs' (Zilog serial port)
@@ -3243,7 +3741,7 @@ diff -ruN proll_18.orig/src/vcons_zs.c proll-patch10/src/vcons_zs.c
 +      return leng;
 +}
 +
-+int vcon_zs_read(struct vconterm *t, char *data, int leng)
++int vcon_zs_read(struct vconterm *t, char *data, __attribute((unused)) int leng)
 +{
 +      unsigned zs_ptr = (unsigned) t->impl;
 +
@@ -3260,14 +3758,14 @@ diff -ruN proll_18.orig/src/vcons_zs.c proll-patch10/src/vcons_zs.c
 +      return ldb_bypass(zs_ptr + ZS_DATA) & 0xff;
 +}
 +
-+void vcon_zs_fini(struct vconterm *t)
++void vcon_zs_fini(__attribute((unused)) struct vconterm *t)
 +{
 +      /* violent crash in the end */
 +      ;
 +}
-diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c
+diff -ruN proll_18.orig/src/vconsole.c proll-patch-15/src/vconsole.c
 --- proll_18.orig/src/vconsole.c       1999-11-08 03:10:28.000000000 +0000
-+++ proll-patch10/src/vconsole.c       2005-04-17 19:23:21.000000000 +0000
++++ proll-patch-15/src/vconsole.c      2005-08-14 10:24:49.000000000 +0000
 @@ -7,12 +7,17 @@
  #include "vconsole.h"
  
@@ -3336,7 +3834,7 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c
  int vcon_write(struct vconterm *t, char *data, int leng)
  {
        int l = leng;
-@@ -40,29 +83,99 @@
+@@ -40,29 +83,101 @@
                if (l <= 0) break;
                c = *data++;    --l;
  
@@ -3358,7 +3856,7 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c
 +                              hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1);
 +                              break;
 +                      default:
-+                              printk("Unhandled escape code '%c'\n", c);
++                              //printk("Unhandled escape code '%c'\n", c);
 +                              break;
 +                      }
                        break;
@@ -3399,8 +3897,10 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c
 +                      case 'm':
 +                              break;
 +                      default:
-+                              printk("Unhandled escape code '%c', par[%d, %d, %d, %d, %d]\n",
++#if 0
++                              printk("Unhandled escape code '%c', par[%d, %d, %d, %d, %d]\n",
 +                                 c, t->vc_par[0], t->vc_par[1], t->vc_par[2], t->vc_par[3], t->vc_par[4]);
++#endif
 +                              break;
 +                      }
                        break;
@@ -3446,7 +3946,7 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c
 +                              } else {
 +                                      t->backc++;
 +                              }
-+                              if (t->vc_x + t->backc >= hcon_qxdim(hconp)) {
++                              if ((unsigned int)t->vc_x + t->backc >= hcon_qxdim(hconp)) {
 +                                      vcon_i_backflush(t);
 +                                      t->vc_x = 0;
 +                                      vcon_i_cursfeed(t);
@@ -3454,10 +3954,32 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c
                        }
                }
        }
-@@ -100,9 +213,62 @@
+@@ -73,7 +188,7 @@
+ static void vcon_i_cursfeed(struct vconterm *t) {
+       struct hconsole *hconp = t->impl;
+-      if (++t->vc_y >= hcon_qydim(hconp)) {
++      if ((unsigned int)++t->vc_y >= hcon_qydim(hconp)) {
+               t->vc_y = hcon_qydim(hconp)-1;
+               hcon_scroll(hconp, 0, hcon_qydim(hconp), SM_UP, 1);
+       }
+@@ -90,22 +205,75 @@
+       t->backp = 0;    t->backc = 0;
+ }
+-int vcon_putch(struct vconterm *t, char c)
++int vcon_putch(__attribute__((unused)) struct vconterm *t, __attribute__((unused)) char c)
+ {
+       return -1;
+ }
+-int vcon_read(struct vconterm *t, char *data, int leng)
++int vcon_read(__attribute__((unused)) struct vconterm *t, __attribute__((unused)) char *data, __attribute__((unused)) int leng)
+ {
        return 0;
  }
  
+-int vcon_getch(struct vconterm *t)
 +static const unsigned char sunkbd_keycode[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, 0, 0,
@@ -3488,7 +4010,7 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c
 +
 +static int shiftstate;
 +
- int vcon_getch(struct vconterm *t)
++int vcon_getch(__attribute__((unused)) struct vconterm *t)
  {
 -      return -1;
 +        int ch;
@@ -3517,10 +4039,14 @@ diff -ruN proll_18.orig/src/vconsole.c proll-patch10/src/vconsole.c
 +      return ch;
  }
  
- void vcon_fini(struct vconterm *t)
-diff -ruN proll_18.orig/src/vconsole.h proll-patch10/src/vconsole.h
+-void vcon_fini(struct vconterm *t)
++void vcon_fini(__attribute__((unused)) struct vconterm *t)
+ {
+       /* violent crash in the end */
+       ;
+diff -ruN proll_18.orig/src/vconsole.h proll-patch-15/src/vconsole.h
 --- proll_18.orig/src/vconsole.h       1999-11-08 00:58:13.000000000 +0000
-+++ proll-patch10/src/vconsole.h       2005-03-02 12:40:12.000000000 +0000
++++ proll-patch-15/src/vconsole.h      2005-03-02 12:40:12.000000000 +0000
 @@ -6,6 +6,8 @@
  #ifndef VCONSOLE_H
  #define VCONSOLE_H
index ff09fc4..bd278d9 100644 (file)
@@ -20,16 +20,20 @@ esac
 
 # register the interpreter for each cpu except for the native one
 if [ $cpu != "i386" ] ; then
-    echo ':i386:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register
-    echo ':i486:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register
+    echo ':i386:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register
+    echo ':i486:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-i386:' > /proc/sys/fs/binfmt_misc/register
 fi
 if [ $cpu != "arm" ] ; then
-    echo   ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-arm:' > /proc/sys/fs/binfmt_misc/register
-    echo   ':armeb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/usr/local/bin/qemu-armeb:' > /proc/sys/fs/binfmt_misc/register
+    echo   ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\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-arm:' > /proc/sys/fs/binfmt_misc/register
+    echo   ':armeb:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-armeb:' > /proc/sys/fs/binfmt_misc/register
 fi
 if [ $cpu != "sparc" ] ; then
-    echo   ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff\xff:/usr/local/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register
+    echo   ':sparc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-sparc:' > /proc/sys/fs/binfmt_misc/register
 fi
 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\xfb\xff\xff\xff:/usr/local/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register
+    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 != "mips" ] ; then
+    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
 fi
index 7f2ed65..ccc9b1e 100644 (file)
@@ -1,6 +1,6 @@
 <HTML>
 <HEAD>
-<!-- Created by texi2html 1.56k from qemu-doc.texi on 4 September 2005 -->
+<!-- Created by texi2html 1.56k from qemu-doc.texi on 19 December 2005 -->
 
 <TITLE>QEMU CPU Emulator User Documentation</TITLE>
 </HEAD>
@@ -20,7 +20,7 @@
 <LI><A NAME="TOC5" HREF="qemu-doc.html#SEC5">2.2 Windows</A>
 <LI><A NAME="TOC6" HREF="qemu-doc.html#SEC6">2.3 Mac OS X</A>
 </UL>
-<LI><A NAME="TOC7" HREF="qemu-doc.html#SEC7">3. QEMU PC System emulator invocation</A>
+<LI><A NAME="TOC7" HREF="qemu-doc.html#SEC7">3. QEMU PC System emulator</A>
 <UL>
 <LI><A NAME="TOC8" HREF="qemu-doc.html#SEC8">3.1 Introduction</A>
 <LI><A NAME="TOC9" HREF="qemu-doc.html#SEC9">3.2 Quick Start</A>
 <LI><A NAME="TOC16" HREF="qemu-doc.html#SEC16">3.6.1 Quick start for disk image creation</A>
 <LI><A NAME="TOC17" HREF="qemu-doc.html#SEC17">3.6.2 Snapshot mode</A>
 <LI><A NAME="TOC18" HREF="qemu-doc.html#SEC18">3.6.3 <CODE>qemu-img</CODE> Invocation</A>
+<LI><A NAME="TOC19" HREF="qemu-doc.html#SEC19">3.6.4 Virtual FAT disk images</A>
 </UL>
-<LI><A NAME="TOC19" HREF="qemu-doc.html#SEC19">3.7 Network emulation</A>
+<LI><A NAME="TOC20" HREF="qemu-doc.html#SEC20">3.7 Network emulation</A>
 <UL>
-<LI><A NAME="TOC20" HREF="qemu-doc.html#SEC20">3.7.1 Using tun/tap network interface</A>
-<LI><A NAME="TOC21" HREF="qemu-doc.html#SEC21">3.7.2 Using the user mode network stack</A>
+<LI><A NAME="TOC21" HREF="qemu-doc.html#SEC21">3.7.1 VLANs</A>
+<LI><A NAME="TOC22" HREF="qemu-doc.html#SEC22">3.7.2 Using TAP network interfaces</A>
+<LI><A NAME="TOC23" HREF="qemu-doc.html#SEC23">3.7.3 Using the user mode network stack</A>
+<LI><A NAME="TOC24" HREF="qemu-doc.html#SEC24">3.7.4 Connecting VLANs between QEMU instances</A>
 </UL>
-<LI><A NAME="TOC22" HREF="qemu-doc.html#SEC22">3.8 Direct Linux Boot</A>
-<LI><A NAME="TOC23" HREF="qemu-doc.html#SEC23">3.9 GDB usage</A>
-<LI><A NAME="TOC24" HREF="qemu-doc.html#SEC24">3.10 Target OS specific information</A>
+<LI><A NAME="TOC25" HREF="qemu-doc.html#SEC25">3.8 Direct Linux Boot</A>
+<LI><A NAME="TOC26" HREF="qemu-doc.html#SEC26">3.9 USB emulation</A>
 <UL>
-<LI><A NAME="TOC25" HREF="qemu-doc.html#SEC25">3.10.1 Linux</A>
-<LI><A NAME="TOC26" HREF="qemu-doc.html#SEC26">3.10.2 Windows</A>
+<LI><A NAME="TOC27" HREF="qemu-doc.html#SEC27">3.9.1 Using virtual USB devices</A>
+<LI><A NAME="TOC28" HREF="qemu-doc.html#SEC28">3.9.2 Using host USB devices on a Linux host</A>
+</UL>
+<LI><A NAME="TOC29" HREF="qemu-doc.html#SEC29">3.10 GDB usage</A>
+<LI><A NAME="TOC30" HREF="qemu-doc.html#SEC30">3.11 Target OS specific information</A>
+<UL>
+<LI><A NAME="TOC31" HREF="qemu-doc.html#SEC31">3.11.1 Linux</A>
+<LI><A NAME="TOC32" HREF="qemu-doc.html#SEC32">3.11.2 Windows</A>
 <UL>
-<LI><A NAME="TOC27" HREF="qemu-doc.html#SEC27">3.10.2.1 SVGA graphic modes support</A>
-<LI><A NAME="TOC28" HREF="qemu-doc.html#SEC28">3.10.2.2 CPU usage reduction</A>
-<LI><A NAME="TOC29" HREF="qemu-doc.html#SEC29">3.10.2.3 Windows 2000 disk full problem</A>
-<LI><A NAME="TOC30" HREF="qemu-doc.html#SEC30">3.10.2.4 Windows 2000 shutdown</A>
-<LI><A NAME="TOC31" HREF="qemu-doc.html#SEC31">3.10.2.5 Share a directory between Unix and Windows</A>
-<LI><A NAME="TOC32" HREF="qemu-doc.html#SEC32">3.10.2.6 Windows XP security problems</A>
+<LI><A NAME="TOC33" HREF="qemu-doc.html#SEC33">3.11.2.1 SVGA graphic modes support</A>
+<LI><A NAME="TOC34" HREF="qemu-doc.html#SEC34">3.11.2.2 CPU usage reduction</A>
+<LI><A NAME="TOC35" HREF="qemu-doc.html#SEC35">3.11.2.3 Windows 2000 disk full problem</A>
+<LI><A NAME="TOC36" HREF="qemu-doc.html#SEC36">3.11.2.4 Windows 2000 shutdown</A>
+<LI><A NAME="TOC37" HREF="qemu-doc.html#SEC37">3.11.2.5 Share a directory between Unix and Windows</A>
+<LI><A NAME="TOC38" HREF="qemu-doc.html#SEC38">3.11.2.6 Windows XP security problems</A>
 </UL>
-<LI><A NAME="TOC33" HREF="qemu-doc.html#SEC33">3.10.3 MS-DOS and FreeDOS</A>
+<LI><A NAME="TOC39" HREF="qemu-doc.html#SEC39">3.11.3 MS-DOS and FreeDOS</A>
 <UL>
-<LI><A NAME="TOC34" HREF="qemu-doc.html#SEC34">3.10.3.1 CPU usage reduction</A>
+<LI><A NAME="TOC40" HREF="qemu-doc.html#SEC40">3.11.3.1 CPU usage reduction</A>
 </UL>
 </UL>
 </UL>
-<LI><A NAME="TOC35" HREF="qemu-doc.html#SEC35">4. QEMU PowerPC System emulator invocation</A>
-<LI><A NAME="TOC36" HREF="qemu-doc.html#SEC36">5. Sparc32 System emulator invocation</A>
-<LI><A NAME="TOC37" HREF="qemu-doc.html#SEC37">6. Sparc64 System emulator invocation</A>
-<LI><A NAME="TOC38" HREF="qemu-doc.html#SEC38">7. MIPS System emulator invocation</A>
-<LI><A NAME="TOC39" HREF="qemu-doc.html#SEC39">8. QEMU User space emulator invocation</A>
+<LI><A NAME="TOC41" HREF="qemu-doc.html#SEC41">4. QEMU System emulator for non PC targets</A>
+<UL>
+<LI><A NAME="TOC42" HREF="qemu-doc.html#SEC42">4.1 QEMU PowerPC System emulator</A>
+<LI><A NAME="TOC43" HREF="qemu-doc.html#SEC43">4.2 Sparc32 System emulator invocation</A>
+<LI><A NAME="TOC44" HREF="qemu-doc.html#SEC44">4.3 Sparc64 System emulator invocation</A>
+<LI><A NAME="TOC45" HREF="qemu-doc.html#SEC45">4.4 MIPS System emulator invocation</A>
+<LI><A NAME="TOC46" HREF="qemu-doc.html#SEC46">4.5 ARM System emulator invocation</A>
+</UL>
+<LI><A NAME="TOC47" HREF="qemu-doc.html#SEC47">5. QEMU Linux User space emulator</A>
 <UL>
-<LI><A NAME="TOC40" HREF="qemu-doc.html#SEC40">8.1 Quick Start</A>
-<LI><A NAME="TOC41" HREF="qemu-doc.html#SEC41">8.2 Wine launch</A>
-<LI><A NAME="TOC42" HREF="qemu-doc.html#SEC42">8.3 Command line options</A>
+<LI><A NAME="TOC48" HREF="qemu-doc.html#SEC48">5.1 Quick Start</A>
+<LI><A NAME="TOC49" HREF="qemu-doc.html#SEC49">5.2 Wine launch</A>
+<LI><A NAME="TOC50" HREF="qemu-doc.html#SEC50">5.3 Command line options</A>
 </UL>
-<LI><A NAME="TOC43" HREF="qemu-doc.html#SEC43">9. Compilation from the sources</A>
+<LI><A NAME="TOC51" HREF="qemu-doc.html#SEC51">6. Compilation from the sources</A>
 <UL>
-<LI><A NAME="TOC44" HREF="qemu-doc.html#SEC44">9.1 Linux/Unix</A>
+<LI><A NAME="TOC52" HREF="qemu-doc.html#SEC52">6.1 Linux/Unix</A>
 <UL>
-<LI><A NAME="TOC45" HREF="qemu-doc.html#SEC45">9.1.1 Compilation</A>
-<LI><A NAME="TOC46" HREF="qemu-doc.html#SEC46">9.1.2 Tested tool versions</A>
+<LI><A NAME="TOC53" HREF="qemu-doc.html#SEC53">6.1.1 Compilation</A>
+<LI><A NAME="TOC54" HREF="qemu-doc.html#SEC54">6.1.2 Tested tool versions</A>
 </UL>
-<LI><A NAME="TOC47" HREF="qemu-doc.html#SEC47">9.2 Windows</A>
-<LI><A NAME="TOC48" HREF="qemu-doc.html#SEC48">9.3 Cross compilation for Windows with Linux</A>
-<LI><A NAME="TOC49" HREF="qemu-doc.html#SEC49">9.4 Mac OS X</A>
+<LI><A NAME="TOC55" HREF="qemu-doc.html#SEC55">6.2 Windows</A>
+<LI><A NAME="TOC56" HREF="qemu-doc.html#SEC56">6.3 Cross compilation for Windows with Linux</A>
+<LI><A NAME="TOC57" HREF="qemu-doc.html#SEC57">6.4 Mac OS X</A>
 </UL>
 </UL>
 <P><HR><P>
@@ -113,9 +125,9 @@ QEMU has two operating modes:
 <LI>
 
 Full system emulation. In this mode, QEMU emulates a full system (for
-example a PC), including a processor and various peripherals. It can
-be used to launch different Operating Systems without rebooting the
-PC or to debug system code.
+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.
 
 <LI>
 
@@ -137,6 +149,8 @@ For system emulation, the following hardware targets are supported:
 <UL>
 <LI>PC (x86 or x86_64 processor)
 
+<LI>ISA PC (old style PC without PCI bus)
+
 <LI>PREP (PowerPC processor)
 
 <LI>G3 BW PowerMac (PowerPC processor)
@@ -147,12 +161,14 @@ For system emulation, the following hardware targets are supported:
 
 <LI>Sun4u (64-bit Sparc processor, in progress)
 
-<LI>Malta board (32-bit MIPS processor, in progress)
+<LI>Malta board (32-bit MIPS processor)
+
+<LI>ARM Integrator/CP (ARM1026E processor)
 
 </UL>
 
 <P>
-For user emulation, x86, PowerPC, ARM, and Sparc32/64 CPUs are supported.
+For user emulation, x86, PowerPC, ARM, MIPS, and Sparc32/64 CPUs are supported.
 
 
 
@@ -160,7 +176,7 @@ For user emulation, x86, PowerPC, ARM, and Sparc32/64 CPUs are supported.
 <H1><A NAME="SEC3" HREF="qemu-doc.html#TOC3">2. Installation</A></H1>
 
 <P>
-If you want to compile QEMU yourself, see section <A HREF="qemu-doc.html#SEC43">9. Compilation from the sources</A>.
+If you want to compile QEMU yourself, see section <A HREF="qemu-doc.html#SEC51">6. Compilation from the sources</A>.
 
 
 
@@ -169,7 +185,7 @@ If you want to compile QEMU yourself, see section <A HREF="qemu-doc.html#SEC43">
 
 <P>
 If a precompiled package is available for your distribution - you just
-have to install it. Otherwise, see section <A HREF="qemu-doc.html#SEC43">9. Compilation from the sources</A>.
+have to install it. Otherwise, see section <A HREF="qemu-doc.html#SEC51">6. Compilation from the sources</A>.
 
 
 
@@ -192,15 +208,15 @@ Download the experimental binary installer at
 
 
 
-<H1><A NAME="SEC7" HREF="qemu-doc.html#TOC7">3. QEMU PC System emulator invocation</A></H1>
+<H1><A NAME="SEC7" HREF="qemu-doc.html#TOC7">3. QEMU PC System emulator</A></H1>
 
 
 
 <H2><A NAME="SEC8" HREF="qemu-doc.html#TOC8">3.1 Introduction</A></H2>
 
 <P>
-The QEMU System emulator simulates the
-following PC peripherals:
+The QEMU PC System emulator simulates the
+following peripherals:
 
 
 
@@ -229,14 +245,36 @@ NE2000 PCI network adapters
 Serial ports
 <LI>
 
-Soundblaster 16 card
+Creative SoundBlaster 16 sound card
+<LI>
+
+ENSONIQ AudioPCI ES1370 sound card
+<LI>
+
+Adlib(OPL2) - Yamaha YM3812 compatible chip
+<LI>
+
+PCI UHCI USB controller and a virtual USB hub.
 </UL>
 
 <P>
+SMP is supported with up to 255 CPUs.
+
+
+<P>
+Note that adlib is only available when QEMU was configured with
+-enable-adlib
+
+
+<P>
 QEMU uses the PC BIOS from the Bochs project and the Plex86/Bochs LGPL
 VGA BIOS.
 
 
+<P>
+QEMU uses YM3812 emulation by Tatsuyuki Satoh.
+
+
 
 
 <H2><A NAME="SEC9" HREF="qemu-doc.html#TOC9">3.2 Quick Start</A></H2>
@@ -271,6 +309,10 @@ usage: qemu [options] [disk_image]
 General options:
 <DL COMPACT>
 
+<DT><SAMP>`-M machine'</SAMP>
+<DD>
+Select the emulated machine (<CODE>-M ?</CODE> for list)
+
 <DT><SAMP>`-fda file'</SAMP>
 <DD>
 <DT><SAMP>`-fdb file'</SAMP>
@@ -309,6 +351,11 @@ the write back by pressing <KBD>C-a s</KBD> (See section <A HREF="qemu-doc.html#
 <DD>
 Set virtual RAM size to <VAR>megs</VAR> megabytes. Default is 128 MB.
 
+<DT><SAMP>`-smp n'</SAMP>
+<DD>
+Simulate an SMP system with <VAR>n</VAR> CPUs. On the PC target, up to 255
+CPUs are supported.
+
 <DT><SAMP>`-nographic'</SAMP>
 <DD>
 Normally, QEMU uses SDL to display the VGA output. With this option,
@@ -334,10 +381,23 @@ de  en-us  fi  fr-be  hr     it  lv  nl-be  pt  sl     tr
 
 The default is <CODE>en-us</CODE>.
 
-<DT><SAMP>`-enable-audio'</SAMP>
+<DT><SAMP>`-audio-help'</SAMP>
+<DD>
+Will show the audio subsystem help: list of drivers, tunable
+parameters.
+
+<DT><SAMP>`-soundhw card1,card2,... or -soundhw all'</SAMP>
 <DD>
-The SB16 emulation is disabled by default as it may give problems with
-Windows. You can enable it manually with this option.
+Enable audio and selected sound hardware. Use ? to print all
+available sound hardware.
+
+
+<PRE>
+qemu -soundhw sb16,adlib hda
+qemu -soundhw es1370 hda
+qemu -soundhw all hda
+qemu -soundhw ?
+</PRE>
 
 <DT><SAMP>`-localtime'</SAMP>
 <DD>
@@ -363,37 +423,121 @@ slows down the IDE transfers).
 </DL>
 
 <P>
+USB options:
+<DL COMPACT>
+
+<DT><SAMP>`-usb'</SAMP>
+<DD>
+Enable the USB driver (will be the default soon)
+
+<DT><SAMP>`-usbdevice devname'</SAMP>
+<DD>
+Add the USB device <VAR>devname</VAR>. See the monitor command
+<CODE>usb_add</CODE> to have more information.
+</DL>
+
+<P>
 Network options:
 
 
 <DL COMPACT>
 
-<DT><SAMP>`-n script'</SAMP>
+<DT><SAMP>`-net nic[,vlan=n][,macaddr=addr]'</SAMP>
 <DD>
-Set TUN/TAP network init script [default=/etc/qemu-ifup]. This script
-is launched to configure the host network interface (usually tun0)
-corresponding to the virtual NE2000 card.
+Create a new Network Interface Card and connect it to VLAN <VAR>n</VAR> (<VAR>n</VAR>
+= 0 is the default). The NIC is currently an NE2000 on the PC
+target. Optionally, the MAC address can be changed. If no
+<SAMP>`-net'</SAMP> option is specified, a single NIC is created.
 
-<DT><SAMP>`-nics n'</SAMP>
+<DT><SAMP>`-net user[,vlan=n]'</SAMP>
 <DD>
-Simulate <VAR>n</VAR> network cards (the default is 1).
+Use the user mode network stack which requires no administrator
+priviledge to run. This is the default if no <SAMP>`-net'</SAMP> option is
+specified.
 
-<DT><SAMP>`-macaddr addr'</SAMP>
+<DT><SAMP>`-net tap[,vlan=n][,fd=h][,ifname=name][,script=file]'</SAMP>
 <DD>
-Set the mac address of the first interface (the format is
-aa:bb:cc:dd:ee:ff in hexa). The mac address is incremented for each
-new network interface.
+Connect the host TAP network interface <VAR>name</VAR> to VLAN <VAR>n</VAR> and
+use the network script <VAR>file</VAR> to configure it. The default
+network script is <TT>`/etc/qemu-ifup'</TT>. If <VAR>name</VAR> is not
+provided, the OS automatically provides one.  <SAMP>`fd=h'</SAMP> can be
+used to specify the handle of an already opened host TAP interface. Example:
+
+
+<PRE>
+qemu linux.img -net nic -net tap
+</PRE>
+
+More complicated example (two NICs, each one connected to a TAP device)
+
+<PRE>
+qemu linux.img -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
+               -net nic,vlan=1 -net tap,vlan=1,ifname=tap1
+</PRE>
 
-<DT><SAMP>`-tun-fd fd'</SAMP>
+<DT><SAMP>`-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]'</SAMP>
 <DD>
-Assumes <VAR>fd</VAR> talks to a tap/tun host network interface and use
-it. Read <A HREF="http://bellard.org/qemu/tetrinet.html">http://bellard.org/qemu/tetrinet.html</A> to have an
-example of its use.
+Connect the VLAN <VAR>n</VAR> to a remote VLAN in another QEMU virtual
+machine using a TCP socket connection. If <SAMP>`listen'</SAMP> is
+specified, QEMU waits for incoming connections on <VAR>port</VAR>
+(<VAR>host</VAR> is optional). <SAMP>`connect'</SAMP> is used to connect to
+another QEMU instance using the <SAMP>`listen'</SAMP> option. <SAMP>`fd=h'</SAMP>
+specifies an already opened TCP socket.
+
+Example:
+
+<PRE>
+# launch a first QEMU instance
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,listen=:1234
+# connect the VLAN 0 of this instance to the VLAN 0 of the first instance
+qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,connect=127.0.0.1:1234
+</PRE>
 
-<DT><SAMP>`-user-net'</SAMP>
+<DT><SAMP>`-net socket[,vlan=n][,fd=h][,mcast=maddr:port]'</SAMP>
 <DD>
-Use the user mode network stack. This is the default if no tun/tap
-network init script is found.
+Create a VLAN <VAR>n</VAR> shared with another QEMU virtual
+machines using a UDP multicast socket, effectively making a bus for 
+every QEMU with same multicast address <VAR>maddr</VAR> and <VAR>port</VAR>.
+NOTES:
+
+<OL>
+<LI>
+
+Several QEMU can be running on different hosts and share same bus (assuming 
+correct multicast setup for these hosts).
+<LI>
+
+mcast support is compatible with User Mode Linux (argument <SAMP>`eth<VAR>N</VAR>=mcast'</SAMP>), see
+<A HREF="http://user-mode-linux.sf.net">http://user-mode-linux.sf.net</A>.
+<LI>Use <SAMP>`fd=h'</SAMP> to specify an already opened UDP multicast socket.
+
+</OL>
+
+Example:
+
+<PRE>
+# launch one QEMU instance
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=230.0.0.1:1234
+# launch another QEMU instance on same "bus"
+qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,mcast=230.0.0.1:1234
+# launch yet another QEMU instance on same "bus"
+qemu linux.img -net nic,macaddr=52:54:00:12:34:58 -net socket,mcast=230.0.0.1:1234
+</PRE>
+
+Example (User Mode Linux compat.):
+
+<PRE>
+# launch QEMU instance (note mcast address selected is UML's default)
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=239.192.168.1:1102
+# launch UML
+/path/to/linux ubd0=/path/to/root_fs eth0=mcast
+</PRE>
+
+<DT><SAMP>`-net none'</SAMP>
+<DD>
+Indicate that no network devices should be configured. It is used to
+override the default configuration which is activated if no
+<SAMP>`-net'</SAMP> options are provided.
 
 <DT><SAMP>`-tftp prefix'</SAMP>
 <DD>
@@ -457,15 +601,10 @@ telnet localhost 5555
 Then when you use on the host <CODE>telnet localhost 5555</CODE>, you
 connect to the guest telnet server.
 
-<DT><SAMP>`-dummy-net'</SAMP>
-<DD>
-Use the dummy network stack: no packet will be received by the network
-cards.
-
 </DL>
 
 <P>
-Linux boot specific. When using this options, you can use a given
+Linux boot specific: When using these options, you can use a given
 Linux kernel without installing it in the disk image. It can be useful
 for easier testing of various kernels.
 
@@ -505,9 +644,23 @@ Virtual console
 <DT><CODE>null</CODE>
 <DD>
 void device
+<DT><CODE>/dev/XXX</CODE>
+<DD>
+[Linux only] Use host tty, e.g. <TT>`/dev/ttyS0'</TT>. The host serial port
+parameters are set according to the emulated ones.
+<DT><CODE>/dev/parportN</CODE>
+<DD>
+[Linux only, parallel port only] Use host parallel port
+<VAR>N</VAR>. Currently only SPP parallel port features can be used.
+<DT><CODE>file:filename</CODE>
+<DD>
+Write output to filename. No character can be read.
 <DT><CODE>stdio</CODE>
 <DD>
 [Unix only] standard input/output
+<DT><CODE>pipe:filename</CODE>
+<DD>
+[Unix only] name pipe <VAR>filename</VAR>
 </DL>
 The default device is <CODE>vc</CODE> in graphical mode and <CODE>stdio</CODE> in
 non graphical mode.
@@ -515,6 +668,16 @@ non graphical mode.
 This option can be used several times to simulate up to 4 serials
 ports.
 
+<DT><SAMP>`-parallel dev'</SAMP>
+<DD>
+Redirect the virtual parallel port to host device <VAR>dev</VAR> (same
+devices as the serial port). On Linux hosts, <TT>`/dev/parportN'</TT> can
+be used to use hardware devices connected on the corresponding host
+parallel port.
+
+This option can be used several times to simulate up to 3 parallel
+ports.
+
 <DT><SAMP>`-monitor dev'</SAMP>
 <DD>
 Redirect the monitor to host device <VAR>dev</VAR> (same devices as the
@@ -524,7 +687,7 @@ non graphical mode.
 
 <DT><SAMP>`-s'</SAMP>
 <DD>
-Wait gdb connection to port 1234 (See section <A HREF="qemu-doc.html#SEC23">3.9 GDB usage</A>). 
+Wait gdb connection to port 1234 (See section <A HREF="qemu-doc.html#SEC29">3.10 GDB usage</A>). 
 <DT><SAMP>`-p port'</SAMP>
 <DD>
 Change gdb connection port.
@@ -542,9 +705,6 @@ translation mode (<VAR>t</VAR>=none, lba or auto). Usually QEMU can guess
 all thoses parameters. This option is useful for old MS-DOS disk
 images.
 
-<DT><SAMP>`-isa'</SAMP>
-<DD>
-Simulate an ISA-only system (default is PCI system).
 <DT><SAMP>`-std-vga'</SAMP>
 <DD>
 Simulate a standard VGA card with Bochs VBE extensions (default is
@@ -671,7 +831,7 @@ show various information about the system state
 
 <DT><SAMP>`info network'</SAMP>
 <DD>
-show the network state
+show the various VLANs and the associated devices
 <DT><SAMP>`info block'</SAMP>
 <DD>
 show the block devices
@@ -681,6 +841,15 @@ show the cpu registers
 <DT><SAMP>`info history'</SAMP>
 <DD>
 show the command line history
+<DT><SAMP>`info pci'</SAMP>
+<DD>
+show emulated PCI device
+<DT><SAMP>`info usb'</SAMP>
+<DD>
+show USB devices plugged on the virtual USB hub
+<DT><SAMP>`info usbhost'</SAMP>
+<DD>
+show all USB host devices
 </DL>
 
 <DT><SAMP>`q or quit'</SAMP>
@@ -815,6 +984,19 @@ intercepts at low level, such as <CODE>ctrl-alt-f1</CODE> in X Window.
 <DD>
 Reset the system.
 
+<DT><SAMP>`usb_add devname'</SAMP>
+<DD>
+Plug the USB device devname to the QEMU virtual USB hub. <VAR>devname</VAR>
+is either a virtual device name (for example <CODE>mouse</CODE>) or a host
+USB device identifier. Host USB device identifiers have the following
+syntax: <CODE>host:bus.addr</CODE> or <CODE>host:vendor_id:product_id</CODE>.
+
+<DT><SAMP>`usb_del devname'</SAMP>
+<DD>
+Remove the USB device <VAR>devname</VAR> from the QEMU virtual USB
+hub. <VAR>devname</VAR> has the syntax <CODE>bus.addr</CODE>. Use the monitor
+command <CODE>info usb</CODE> to see the devices you can remove.
+
 </DL>
 
 
@@ -1006,21 +1188,90 @@ from the displayed size.
 
 
 
-<H2><A NAME="SEC19" HREF="qemu-doc.html#TOC19">3.7 Network emulation</A></H2>
+<H3><A NAME="SEC19" HREF="qemu-doc.html#TOC19">3.6.4 Virtual FAT disk images</A></H3>
+
+<P>
+QEMU can automatically create a virtual FAT disk image from a
+directory tree. In order to use it, just type:
+
+
+
+<PRE>
+qemu linux.img -hdb fat:/my_directory
+</PRE>
+
+<P>
+Then you access access to all the files in the <TT>`/my_directory'</TT>
+directory without having to copy them in a disk image or to export
+them via SAMBA or NFS. The default access is <EM>read-only</EM>.
+
+
+<P>
+Floppies can be emulated with the <CODE>:floppy:</CODE> option:
+
+
+
+<PRE>
+qemu linux.img -fda fat:floppy:/my_directory
+</PRE>
+
+<P>
+A read/write support is available for testing (beta stage) with the
+<CODE>:rw:</CODE> option:
+
+
+
+<PRE>
+qemu linux.img -fda fat:floppy:rw:/my_directory
+</PRE>
 
 <P>
-QEMU simulates up to 6 networks cards (NE2000 boards). Each card can
-be connected to a specific host network interface.
+What you should <EM>never</EM> do:
 
+<UL>
+<LI>use non-ASCII filenames ;
 
+<LI>use "-snapshot" together with ":rw:" ;
 
+<LI>expect it to work when loadvm'ing ;
 
-<H3><A NAME="SEC20" HREF="qemu-doc.html#TOC20">3.7.1 Using tun/tap network interface</A></H3>
+<LI>write to the FAT directory on the host system while accessing it with the guest system.
+
+</UL>
+
+
+
+<H2><A NAME="SEC20" HREF="qemu-doc.html#TOC20">3.7 Network emulation</A></H2>
 
 <P>
-This is the standard way to emulate network. QEMU adds a virtual
-network device on your host (called <CODE>tun0</CODE>), and you can then
-configure it as if it was a real ethernet card.
+QEMU can simulate several networks cards (NE2000 boards 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
+network stack can replace the TAP device to have a basic network
+connection.
+
+
+
+
+<H3><A NAME="SEC21" HREF="qemu-doc.html#TOC21">3.7.1 VLANs</A></H3>
+
+<P>
+QEMU simulates several VLANs. A VLAN can be symbolised as a virtual
+connection between several network devices. These devices can be for
+example QEMU virtual Ethernet cards or virtual Host ethernet devices
+(TAP devices).
+
+
+
+
+<H3><A NAME="SEC22" HREF="qemu-doc.html#TOC22">3.7.2 Using TAP network interfaces</A></H3>
+
+<P>
+This is the standard way to connect QEMU to a real network. QEMU adds
+a virtual network device on your host (called <CODE>tapN</CODE>), and you
+can then configure it as if it was a real ethernet card.
 
 
 <P>
@@ -1028,31 +1279,32 @@ As an example, you can download the <TT>`linux-test-xxx.tar.gz'</TT>
 archive and copy the script <TT>`qemu-ifup'</TT> in <TT>`/etc'</TT> and
 configure properly <CODE>sudo</CODE> so that the command <CODE>ifconfig</CODE>
 contained in <TT>`qemu-ifup'</TT> can be executed as root. You must verify
-that your host kernel supports the TUN/TAP network interfaces: the
+that your host kernel supports the TAP network interfaces: the
 device <TT>`/dev/net/tun'</TT> must be present.
 
 
 <P>
-See section <A HREF="qemu-doc.html#SEC22">3.8 Direct Linux Boot</A> to have an example of network use with a
-Linux distribution.
+See section <A HREF="qemu-doc.html#SEC25">3.8 Direct Linux Boot</A> to have an example of network use with a
+Linux distribution and section <A HREF="qemu-doc.html#SEC10">3.3 Invocation</A> to have examples of
+command lines using the TAP network interfaces.
 
 
 
 
-<H3><A NAME="SEC21" HREF="qemu-doc.html#TOC21">3.7.2 Using the user mode network stack</A></H3>
+<H3><A NAME="SEC23" HREF="qemu-doc.html#TOC23">3.7.3 Using the user mode network stack</A></H3>
 
 <P>
-By using the option <SAMP>`-user-net'</SAMP> or if you have no tun/tap init
-script, QEMU uses a completely user mode network stack (you don't need
-root priviledge to use the virtual network). The virtual network
-configuration is the following:
+By using the option <SAMP>`-net user'</SAMP> (default configuration if no
+<SAMP>`-net'</SAMP> option is specified), QEMU uses a completely user mode
+network stack (you don't need root priviledge to use the virtual
+network). The virtual network configuration is the following:
 
 
 
 <PRE>
 
-QEMU Virtual Machine    &#60;------&#62;  Firewall/DHCP server &#60;-----&#62; Internet
-     (10.0.2.x)            |          (10.0.2.2)
+         QEMU VLAN      &#60;------&#62;  Firewall/DHCP server &#60;-----&#62; Internet
+                           |          (10.0.2.2)
                            |
                            ----&#62;  DNS server (10.0.2.3)
                            |     
@@ -1062,7 +1314,8 @@ QEMU Virtual Machine    &#60;------&#62;  Firewall/DHCP server &#60;-----&#62; I
 <P>
 The QEMU VM behaves as if it was behind a firewall which blocks all
 incoming connections. You can use a DHCP client to automatically
-configure the network in the QEMU VM.
+configure the network in the QEMU VM. The DHCP server assign addresses
+to the hosts starting from 10.0.2.15.
 
 
 <P>
@@ -1090,7 +1343,17 @@ redirect X11, telnet or SSH connections.
 
 
 
-<H2><A NAME="SEC22" HREF="qemu-doc.html#TOC22">3.8 Direct Linux Boot</A></H2>
+<H3><A NAME="SEC24" HREF="qemu-doc.html#TOC24">3.7.4 Connecting VLANs between QEMU instances</A></H3>
+
+<P>
+Using the <SAMP>`-net socket'</SAMP> option, it is possible to make VLANs
+that span several QEMU instances. See section <A HREF="qemu-doc.html#SEC10">3.3 Invocation</A> to have a
+basic example.
+
+
+
+
+<H2><A NAME="SEC25" HREF="qemu-doc.html#TOC25">3.8 Direct Linux Boot</A></H2>
 
 <P>
 This section explains how to launch a Linux kernel inside QEMU without
@@ -1254,7 +1517,111 @@ Lawton for the plex86 Project (<A HREF="www.plex86.org">www.plex86.org</A>).
 
 
 
-<H2><A NAME="SEC23" HREF="qemu-doc.html#TOC23">3.9 GDB usage</A></H2>
+<H2><A NAME="SEC26" HREF="qemu-doc.html#TOC26">3.9 USB emulation</A></H2>
+
+<P>
+QEMU emulates a PCI UHCI USB controller and a 8 port USB hub connected
+to it. You can virtually plug to the hub virtual USB devices or real
+host USB devices (experimental, works only on Linux hosts).
+
+
+
+
+<H3><A NAME="SEC27" HREF="qemu-doc.html#TOC27">3.9.1 Using virtual USB devices</A></H3>
+
+<P>
+A virtual USB mouse device is available for testing in QEMU.
+
+
+<P>
+You can try it with the following monitor commands:
+
+
+
+<PRE>
+# add the mouse device
+(qemu) usb_add mouse 
+
+# show the virtual USB devices plugged on the QEMU Virtual USB hub
+(qemu) info usb
+  Device 0.3, speed 12 Mb/s
+
+# after some time you can try to remove the mouse
+(qemu) usb_del 0.3
+</PRE>
+
+<P>
+The option <SAMP>`-usbdevice'</SAMP> is similar to the monitor command
+<CODE>usb_add</CODE>.
+
+
+
+
+<H3><A NAME="SEC28" HREF="qemu-doc.html#TOC28">3.9.2 Using host USB devices on a Linux host</A></H3>
+
+<P>
+WARNING: this is an experimental feature. QEMU will slow down when
+using it. USB devices requiring real time streaming (i.e. USB Video
+Cameras) are not supported yet.
+
+
+
+<OL>
+<LI>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 <TT>`mydriver.o'</TT>
+to <TT>`mydriver.o.disabled'</TT>.
+
+<LI>Verify that <TT>`/proc/bus/usb'</TT> is working (most Linux distributions should enable it by default). You should see something like that:
+
+
+<PRE>
+ls /proc/bus/usb
+001  devices  drivers
+</PRE>
+
+<LI>Since only root can access to the USB devices directly, you can either launch QEMU as root or change the permissions of the USB devices you want to use. For testing, the following suffices:
+
+
+<PRE>
+chown -R myuid /proc/bus/usb
+</PRE>
+
+<LI>Launch QEMU and do in the monitor:
+
+
+<PRE>
+info usbhost
+  Device 1.2, speed 480 Mb/s
+    Class 00: USB device 1234:5678, USB DISK
+</PRE>
+
+You should see the list of the devices you can use (Never try to use
+hubs, it won't work).
+
+<LI>Add the device in QEMU by using:
+
+
+<PRE>
+usb_add host:1234:5678
+</PRE>
+
+Normally the guest OS should report that a new USB device is
+plugged. You can use the option <SAMP>`-usbdevice'</SAMP> to do the same.
+
+<LI>Now you can try to use the host USB device in QEMU.
+
+</OL>
+
+<P>
+When relaunching QEMU, you may have to unplug and plug again the USB
+device to make it work again (this is a bug).
+
+
+
+
+<H2><A NAME="SEC29" HREF="qemu-doc.html#TOC29">3.10 GDB usage</A></H2>
 
 <P>
 QEMU has a primitive support to work with gdb, so that you can do
@@ -1312,11 +1679,11 @@ Use <CODE>set architecture i8086</CODE> to dump 16 bit code. Then use
 
 
 
-<H2><A NAME="SEC24" HREF="qemu-doc.html#TOC24">3.10 Target OS specific information</A></H2>
+<H2><A NAME="SEC30" HREF="qemu-doc.html#TOC30">3.11 Target OS specific information</A></H2>
 
 
 
-<H3><A NAME="SEC25" HREF="qemu-doc.html#TOC25">3.10.1 Linux</A></H3>
+<H3><A NAME="SEC31" HREF="qemu-doc.html#TOC31">3.11.1 Linux</A></H3>
 
 <P>
 To have access to SVGA graphic modes under X11, use the <CODE>vesa</CODE> or
@@ -1341,7 +1708,7 @@ patch by default. Newer kernels don't have it.
 
 
 
-<H3><A NAME="SEC26" HREF="qemu-doc.html#TOC26">3.10.2 Windows</A></H3>
+<H3><A NAME="SEC32" HREF="qemu-doc.html#TOC32">3.11.2 Windows</A></H3>
 
 <P>
 If you have a slow host, using Windows 95 is better as it gives the
@@ -1350,7 +1717,7 @@ best speed. Windows 2000 is also a good choice.
 
 
 
-<H4><A NAME="SEC27" HREF="qemu-doc.html#TOC27">3.10.2.1 SVGA graphic modes support</A></H4>
+<H4><A NAME="SEC33" HREF="qemu-doc.html#TOC33">3.11.2.1 SVGA graphic modes support</A></H4>
 
 <P>
 QEMU emulates a Cirrus Logic GD5446 Video
@@ -1361,7 +1728,7 @@ depth in the guest and the host OS.
 
 
 
-<H4><A NAME="SEC28" HREF="qemu-doc.html#TOC28">3.10.2.2 CPU usage reduction</A></H4>
+<H4><A NAME="SEC34" HREF="qemu-doc.html#TOC34">3.11.2.2 CPU usage reduction</A></H4>
 
 <P>
 Windows 9x does not correctly use the CPU HLT
@@ -1373,7 +1740,7 @@ problem. Note that no such tool is needed for NT, 2000 or XP.
 
 
 
-<H4><A NAME="SEC29" HREF="qemu-doc.html#TOC29">3.10.2.3 Windows 2000 disk full problem</A></H4>
+<H4><A NAME="SEC35" HREF="qemu-doc.html#TOC35">3.11.2.3 Windows 2000 disk full problem</A></H4>
 
 <P>
 Windows 2000 has a bug which gives a disk full problem during its
@@ -1385,7 +1752,7 @@ IDE transfers).
 
 
 
-<H4><A NAME="SEC30" HREF="qemu-doc.html#TOC30">3.10.2.4 Windows 2000 shutdown</A></H4>
+<H4><A NAME="SEC36" HREF="qemu-doc.html#TOC36">3.11.2.4 Windows 2000 shutdown</A></H4>
 
 <P>
 Windows 2000 cannot automatically shutdown in QEMU although Windows 98
@@ -1404,7 +1771,7 @@ correctly instructs QEMU to shutdown at the appropriate moment.
 
 
 
-<H4><A NAME="SEC31" HREF="qemu-doc.html#TOC31">3.10.2.5 Share a directory between Unix and Windows</A></H4>
+<H4><A NAME="SEC37" HREF="qemu-doc.html#TOC37">3.11.2.5 Share a directory between Unix and Windows</A></H4>
 
 <P>
 See section <A HREF="qemu-doc.html#SEC10">3.3 Invocation</A> about the help of the option <SAMP>`-smb'</SAMP>.
@@ -1412,7 +1779,7 @@ See section <A HREF="qemu-doc.html#SEC10">3.3 Invocation</A> about the help of t
 
 
 
-<H4><A NAME="SEC32" HREF="qemu-doc.html#TOC32">3.10.2.6 Windows XP security problems</A></H4>
+<H4><A NAME="SEC38" HREF="qemu-doc.html#TOC38">3.11.2.6 Windows XP security problems</A></H4>
 
 <P>
 Some releases of Windows XP install correctly but give a security
@@ -1434,11 +1801,11 @@ Future QEMU releases are likely to correct this bug.
 
 
 
-<H3><A NAME="SEC33" HREF="qemu-doc.html#TOC33">3.10.3 MS-DOS and FreeDOS</A></H3>
+<H3><A NAME="SEC39" HREF="qemu-doc.html#TOC39">3.11.3 MS-DOS and FreeDOS</A></H3>
 
 
 
-<H4><A NAME="SEC34" HREF="qemu-doc.html#TOC34">3.10.3.1 CPU usage reduction</A></H4>
+<H4><A NAME="SEC40" HREF="qemu-doc.html#TOC40">3.11.3.1 CPU usage reduction</A></H4>
 
 <P>
 DOS does not correctly use the CPU HLT instruction. The result is that
@@ -1449,7 +1816,17 @@ problem.
 
 
 
-<H1><A NAME="SEC35" HREF="qemu-doc.html#TOC35">4. QEMU PowerPC System emulator invocation</A></H1>
+<H1><A NAME="SEC41" HREF="qemu-doc.html#TOC41">4. QEMU System emulator for non PC targets</A></H1>
+
+<P>
+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.
+
+
+
+
+<H2><A NAME="SEC42" HREF="qemu-doc.html#TOC42">4.1 QEMU PowerPC System emulator</A></H2>
 
 <P>
 Use the executable <TT>`qemu-system-ppc'</TT> to simulate a complete PREP
@@ -1516,12 +1893,7 @@ PC compatible keyboard and mouse.
 
 <P>
 QEMU uses the Open Hack'Ware Open Firmware Compatible BIOS available at
-<A HREF="http://site.voila.fr/jmayer/OpenHackWare/index.htm">http://site.voila.fr/jmayer/OpenHackWare/index.htm</A>.
-
-
-<P>
-You can read the qemu PC system emulation chapter to have more
-informations about QEMU usage.
+<A HREF="http://perso.magic.fr/l_indien/OpenHackWare/index.htm">http://perso.magic.fr/l_indien/OpenHackWare/index.htm</A>.
 
 
 <P>
@@ -1530,10 +1902,6 @@ The following options are specific to the PowerPC emulation:
 
 <DL COMPACT>
 
-<DT><SAMP>`-prep'</SAMP>
-<DD>
-Simulate a PREP system (default is PowerMAC)
-
 <DT><SAMP>`-g WxH[xDEPTH]'</SAMP>
 <DD>
 Set the initial VGA graphic mode. The default is 800x600x15.
@@ -1542,12 +1910,12 @@ Set the initial VGA graphic mode. The default is 800x600x15.
 
 <P>
 More information is available at
-<A HREF="http://jocelyn.mayer.free.fr/qemu-ppc/">http://jocelyn.mayer.free.fr/qemu-ppc/</A>.
+<A HREF="http://perso.magic.fr/l_indien/qemu-ppc/">http://perso.magic.fr/l_indien/qemu-ppc/</A>.
 
 
 
 
-<H1><A NAME="SEC36" HREF="qemu-doc.html#TOC36">5. Sparc32 System emulator invocation</A></H1>
+<H2><A NAME="SEC43" HREF="qemu-doc.html#TOC43">4.2 Sparc32 System emulator invocation</A></H2>
 
 <P>
 Use the executable <TT>`qemu-system-sparc'</TT> to simulate a JavaStation
@@ -1614,7 +1982,7 @@ Set the initial TCX graphic mode. The default is 1024x768.
 
 
 
-<H1><A NAME="SEC37" HREF="qemu-doc.html#TOC37">6. Sparc64 System emulator invocation</A></H1>
+<H2><A NAME="SEC44" HREF="qemu-doc.html#TOC44">4.3 Sparc64 System emulator invocation</A></H2>
 
 <P>
 Use the executable <TT>`qemu-system-sparc64'</TT> to simulate a Sun4u machine.
@@ -1643,20 +2011,66 @@ PC-compatible serial ports
 
 
 
-<H1><A NAME="SEC38" HREF="qemu-doc.html#TOC38">7. MIPS System emulator invocation</A></H1>
+<H2><A NAME="SEC45" HREF="qemu-doc.html#TOC45">4.4 MIPS System emulator invocation</A></H2>
 
 <P>
 Use the executable <TT>`qemu-system-mips'</TT> to simulate a MIPS machine.
-The emulator begins to launch a Linux kernel.
+The emulator is able to boot a Linux kernel and to run a Linux Debian
+installation from NFS. The following devices are emulated:
+
+
+
+<UL>
+<LI>
+
+MIPS R4K CPU
+<LI>
+
+PC style serial port
+<LI>
+
+NE2000 network card
+</UL>
+
+<P>
+More information is available in the QEMU mailing-list archive.
+
+
+
+
+<H2><A NAME="SEC46" HREF="qemu-doc.html#TOC46">4.5 ARM System emulator invocation</A></H2>
+
+<P>
+Use the executable <TT>`qemu-system-arm'</TT> to simulate a ARM
+machine. The ARM Integrator/CP board is emulated with the following
+devices:
+
+
+
+<UL>
+<LI>
+
+ARM1026E CPU
+<LI>
+
+Two PL011 UARTs
+<LI>
+
+SMC 91c111 Ethernet adapter
+</UL>
+
+<P>
+A Linux 2.6 test image is available on the QEMU web site. More
+information is available in the QEMU mailing-list archive.
 
 
 
 
-<H1><A NAME="SEC39" HREF="qemu-doc.html#TOC39">8. QEMU User space emulator invocation</A></H1>
+<H1><A NAME="SEC47" HREF="qemu-doc.html#TOC47">5. QEMU Linux User space emulator</A></H1>
 
 
 
-<H2><A NAME="SEC40" HREF="qemu-doc.html#TOC40">8.1 Quick Start</A></H2>
+<H2><A NAME="SEC48" HREF="qemu-doc.html#TOC48">5.1 Quick Start</A></H2>
 
 <P>
 In order to launch a Linux process, QEMU needs the process executable
@@ -1718,7 +2132,7 @@ qemu-i386 /usr/local/qemu-i386/bin/qemu-i386 /usr/local/qemu-i386/bin/ls-i386
 
 
 
-<H2><A NAME="SEC41" HREF="qemu-doc.html#TOC41">8.2 Wine launch</A></H2>
+<H2><A NAME="SEC49" HREF="qemu-doc.html#TOC49">5.2 Wine launch</A></H2>
 
 
 <UL>
@@ -1753,7 +2167,7 @@ qemu-i386 /usr/local/qemu-i386/wine/bin/wine /usr/local/qemu-i386/wine/c/Program
 
 
 
-<H2><A NAME="SEC42" HREF="qemu-doc.html#TOC42">8.3 Command line options</A></H2>
+<H2><A NAME="SEC50" HREF="qemu-doc.html#TOC50">5.3 Command line options</A></H2>
 
 
 <PRE>
@@ -1789,15 +2203,15 @@ Act as if the host page size was 'pagesize' bytes
 
 
 
-<H1><A NAME="SEC43" HREF="qemu-doc.html#TOC43">9. Compilation from the sources</A></H1>
+<H1><A NAME="SEC51" HREF="qemu-doc.html#TOC51">6. Compilation from the sources</A></H1>
 
 
 
-<H2><A NAME="SEC44" HREF="qemu-doc.html#TOC44">9.1 Linux/Unix</A></H2>
+<H2><A NAME="SEC52" HREF="qemu-doc.html#TOC52">6.1 Linux/Unix</A></H2>
 
 
 
-<H3><A NAME="SEC45" HREF="qemu-doc.html#TOC45">9.1.1 Compilation</A></H3>
+<H3><A NAME="SEC53" HREF="qemu-doc.html#TOC53">6.1.1 Compilation</A></H3>
 
 <P>
 First you must decompress the sources:
@@ -1829,7 +2243,7 @@ to install QEMU in <TT>`/usr/local'</TT>.
 
 
 
-<H3><A NAME="SEC46" HREF="qemu-doc.html#TOC46">9.1.2 Tested tool versions</A></H3>
+<H3><A NAME="SEC54" HREF="qemu-doc.html#TOC54">6.1.2 Tested tool versions</A></H3>
 
 <P>
 In order to compile QEMU succesfully, it is very important that you
@@ -1868,7 +2282,7 @@ variables. You must use gcc 3.x on PowerPC.
 
 
 
-<H2><A NAME="SEC47" HREF="qemu-doc.html#TOC47">9.2 Windows</A></H2>
+<H2><A NAME="SEC55" HREF="qemu-doc.html#TOC55">6.2 Windows</A></H2>
 
 
 <UL>
@@ -1905,7 +2319,7 @@ correct SDL directory when invoked.
 
 
 
-<H2><A NAME="SEC48" HREF="qemu-doc.html#TOC48">9.3 Cross compilation for Windows with Linux</A></H2>
+<H2><A NAME="SEC56" HREF="qemu-doc.html#TOC56">6.3 Cross compilation for Windows with Linux</A></H2>
 
 
 <UL>
@@ -1947,7 +2361,7 @@ QEMU for Win32.
 
 
 
-<H2><A NAME="SEC49" HREF="qemu-doc.html#TOC49">9.4 Mac OS X</A></H2>
+<H2><A NAME="SEC57" HREF="qemu-doc.html#TOC57">6.4 Mac OS X</A></H2>
 
 <P>
 The Mac OS X patches are not fully merged in QEMU, so you should look
@@ -1956,7 +2370,7 @@ information.
 
 
 <P><HR><P>
-This document was generated on 4 September 2005 using
+This document was generated on 19 December 2005 using
 <A HREF="http://wwwinfo.cern.ch/dis/texi2html/">texi2html</A>&nbsp;1.56k.
 </BODY>
 </HTML>
index 526bd4b..97cb49a 100644 (file)
@@ -22,9 +22,9 @@ QEMU has two operating modes:
 
 @item 
 Full system emulation. In this mode, QEMU emulates a full system (for
-example a PC), including a processor and various peripherals. It can
-be used to launch different Operating Systems without rebooting the
-PC or to debug system code.
+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 
 User mode emulation (Linux host only). In this mode, QEMU can launch
@@ -40,15 +40,17 @@ performance.
 For system emulation, the following hardware targets are supported:
 @itemize
 @item PC (x86 or x86_64 processor)
+@item ISA PC (old style PC without PCI bus)
 @item PREP (PowerPC processor)
 @item G3 BW PowerMac (PowerPC processor)
 @item Mac99 PowerMac (PowerPC processor, in progress)
 @item Sun4m (32-bit Sparc processor)
 @item Sun4u (64-bit Sparc processor, in progress)
-@item Malta board (32-bit MIPS processor, in progress)
+@item Malta board (32-bit MIPS processor)
+@item ARM Integrator/CP (ARM1026E processor)
 @end itemize
 
-For user emulation, x86, PowerPC, ARM, and Sparc32/64 CPUs are supported.
+For user emulation, x86, PowerPC, ARM, MIPS, and Sparc32/64 CPUs are supported.
 
 @chapter Installation
 
@@ -69,14 +71,14 @@ Download the experimental binary installer at
 Download the experimental binary installer at
 @url{http://www.freeoszoo.org/download.php}.
 
-@chapter QEMU PC System emulator invocation
+@chapter QEMU PC System emulator
 
 @section Introduction
 
 @c man begin DESCRIPTION
 
-The QEMU System emulator simulates the
-following PC peripherals:
+The QEMU PC System emulator simulates the
+following peripherals:
 
 @itemize @minus
 @item 
@@ -95,12 +97,25 @@ NE2000 PCI network adapters
 @item
 Serial ports
 @item
-Soundblaster 16 card
+Creative SoundBlaster 16 sound card
+@item
+ENSONIQ AudioPCI ES1370 sound card
+@item
+Adlib(OPL2) - Yamaha YM3812 compatible chip
+@item
+PCI UHCI USB controller and a virtual USB hub.
 @end itemize
 
+SMP is supported with up to 255 CPUs.
+
+Note that adlib is only available when QEMU was configured with
+-enable-adlib
+
 QEMU uses the PC BIOS from the Bochs project and the Plex86/Bochs LGPL
 VGA BIOS.
 
+QEMU uses YM3812 emulation by Tatsuyuki Satoh.
+
 @c man end
 
 @section Quick Start
@@ -127,6 +142,9 @@ usage: qemu [options] [disk_image]
 
 General options:
 @table @option
+@item -M machine
+Select the emulated machine (@code{-M ?} for list)
+
 @item -fda file
 @item -fdb file
 Use @var{file} as floppy disk 0/1 image (@xref{disk_images}). You can
@@ -155,6 +173,10 @@ the write back by pressing @key{C-a s} (@xref{disk_images}).
 @item -m megs
 Set virtual RAM size to @var{megs} megabytes. Default is 128 MB.
 
+@item -smp n
+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,
@@ -179,10 +201,22 @@ de  en-us  fi  fr-be  hr     it  lv  nl-be  pt  sl     tr
 
 The default is @code{en-us}.
 
-@item -enable-audio
+@item -audio-help
 
-The SB16 emulation is disabled by default as it may give problems with
-Windows. You can enable it manually with this option.
+Will show the audio subsystem help: list of drivers, tunable
+parameters.
+
+@item -soundhw card1,card2,... or -soundhw all
+
+Enable audio and selected sound hardware. Use ? to print all
+available sound hardware.
+
+@example
+qemu -soundhw sb16,adlib hda
+qemu -soundhw es1370 hda
+qemu -soundhw all hda
+qemu -soundhw ?
+@end example
 
 @item -localtime
 Set the real time clock to local time (the default is to UTC
@@ -203,33 +237,105 @@ slows down the IDE transfers).
 
 @end table
 
+USB options:
+@table @option
+
+@item -usb
+Enable the USB driver (will be the default soon)
+
+@item -usbdevice devname
+Add the USB device @var{devname}. See the monitor command
+@code{usb_add} to have more information.
+@end table
+
 Network options:
 
 @table @option
 
-@item -n script      
-Set TUN/TAP network init script [default=/etc/qemu-ifup]. This script
-is launched to configure the host network interface (usually tun0)
-corresponding to the virtual NE2000 card.
+@item -net nic[,vlan=n][,macaddr=addr]
+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
+target. Optionally, the MAC address can be changed. If no
+@option{-net} option is specified, a single NIC is created.
 
-@item -nics n
+@item -net user[,vlan=n]
+Use the user mode network stack which requires no administrator
+priviledge to run. This is the default if no @option{-net} option is
+specified.
 
-Simulate @var{n} network cards (the default is 1).
+@item -net tap[,vlan=n][,fd=h][,ifname=name][,script=file]
+Connect the host TAP network interface @var{name} to VLAN @var{n} and
+use the network script @var{file} to configure it. The default
+network script is @file{/etc/qemu-ifup}. If @var{name} is not
+provided, the OS automatically provides one.  @option{fd=h} can be
+used to specify the handle of an already opened host TAP interface. Example:
+
+@example
+qemu linux.img -net nic -net tap
+@end example
 
-@item -macaddr addr   
+More complicated example (two NICs, each one connected to a TAP device)
+@example
+qemu linux.img -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
+               -net nic,vlan=1 -net tap,vlan=1,ifname=tap1
+@end example
 
-Set the mac address of the first interface (the format is
-aa:bb:cc:dd:ee:ff in hexa). The mac address is incremented for each
-new network interface.
 
-@item -tun-fd fd
-Assumes @var{fd} talks to a tap/tun host network interface and use
-it. Read @url{http://bellard.org/qemu/tetrinet.html} to have an
-example of its use.
+@item -net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]
 
-@item -user-net 
-Use the user mode network stack. This is the default if no tun/tap
-network init script is found.
+Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual
+machine using a TCP socket connection. If @option{listen} is
+specified, QEMU waits for incoming connections on @var{port}
+(@var{host} is optional). @option{connect} is used to connect to
+another QEMU instance using the @option{listen} option. @option{fd=h}
+specifies an already opened TCP socket.
+
+Example:
+@example
+# launch a first QEMU instance
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,listen=:1234
+# connect the VLAN 0 of this instance to the VLAN 0 of the first instance
+qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,connect=127.0.0.1:1234
+@end example
+
+@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 
+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 
+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.
+@end enumerate
+
+Example:
+@example
+# launch one QEMU instance
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=230.0.0.1:1234
+# launch another QEMU instance on same "bus"
+qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,mcast=230.0.0.1:1234
+# launch yet another QEMU instance on same "bus"
+qemu linux.img -net nic,macaddr=52:54:00:12:34:58 -net socket,mcast=230.0.0.1:1234
+@end example
+
+Example (User Mode Linux compat.):
+@example
+# launch QEMU instance (note mcast address selected is UML's default)
+qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=239.192.168.1:1102
+# launch UML
+/path/to/linux ubd0=/path/to/root_fs eth0=mcast
+@end example
+
+@item -net none
+Indicate that no network devices should be configured. It is used to
+override the default configuration which is activated if no
+@option{-net} options are provided.
 
 @item -tftp prefix
 When using the user mode network stack, activate a built-in TFTP
@@ -287,13 +393,9 @@ telnet localhost 5555
 Then when you use on the host @code{telnet localhost 5555}, you
 connect to the guest telnet server.
 
-@item -dummy-net 
-Use the dummy network stack: no packet will be received by the network
-cards.
-
 @end table
 
-Linux boot specific. When using this options, you can use a given
+Linux boot specific: When using these options, you can use a given
 Linux kernel without installing it in the disk image. It can be useful
 for easier testing of various kernels.
 
@@ -323,8 +425,18 @@ Virtual console
 [Linux only] Pseudo TTY (a new PTY is automatically allocated)
 @item null
 void device
+@item /dev/XXX
+[Linux only] Use host tty, e.g. @file{/dev/ttyS0}. The host serial port
+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.
+@item file:filename
+Write output to filename. No character can be read.
 @item stdio
 [Unix only] standard input/output
+@item pipe:filename
+[Unix only] name pipe @var{filename}
 @end table
 The default device is @code{vc} in graphical mode and @code{stdio} in
 non graphical mode.
@@ -332,6 +444,15 @@ non graphical mode.
 This option can be used several times to simulate up to 4 serials
 ports.
 
+@item -parallel dev
+Redirect the virtual parallel port to host device @var{dev} (same
+devices as the serial port). On Linux hosts, @file{/dev/parportN} can
+be used to use hardware devices connected on the corresponding host
+parallel port.
+
+This option can be used several times to simulate up to 3 parallel
+ports.
+
 @item -monitor dev
 Redirect the monitor to host device @var{dev} (same devices as the
 serial port).
@@ -353,8 +474,6 @@ translation mode (@var{t}=none, lba or auto). Usually QEMU can guess
 all thoses parameters. This option is useful for old MS-DOS disk
 images.
 
-@item -isa
-Simulate an ISA-only system (default is PCI system).
 @item -std-vga
 Simulate a standard VGA card with Bochs VBE extensions (default is
 Cirrus Logic GD5446 PCI VGA)
@@ -464,13 +583,19 @@ show various information about the system state
 
 @table @option
 @item info network
-show the network state
+show the various VLANs and the associated devices
 @item info block
 show the block devices
 @item info registers
 show the cpu registers
 @item info history
 show the command line history
+@item info pci
+show emulated PCI device
+@item info usb
+show USB devices plugged on the virtual USB hub
+@item info usbhost
+show all USB host devices
 @end table
 
 @item q or quit
@@ -582,6 +707,19 @@ intercepts at low level, such as @code{ctrl-alt-f1} in X Window.
 
 Reset the system.
 
+@item usb_add devname
+
+Plug the USB device devname to the QEMU virtual USB hub. @var{devname}
+is either a virtual device name (for example @code{mouse}) or a host
+USB device identifier. Host USB device identifiers have the following
+syntax: @code{host:bus.addr} or @code{host:vendor_id:product_id}.
+
+@item usb_del devname
+
+Remove the USB device @var{devname} from the QEMU virtual USB
+hub. @var{devname} has the syntax @code{bus.addr}. Use the monitor
+command @code{info usb} to see the devices you can remove.
+
 @end table
 
 @subsection Integer expressions
@@ -622,38 +760,85 @@ command (or @key{C-a s} in the serial console).
 
 @include qemu-img.texi
 
+@subsection Virtual FAT disk images
+
+QEMU can automatically create a virtual FAT disk image from a
+directory tree. In order to use it, just type:
+
+@example 
+qemu linux.img -hdb fat:/my_directory
+@end example
+
+Then you access access to all the files in the @file{/my_directory}
+directory without having to copy them in a disk image or to export
+them via SAMBA or NFS. The default access is @emph{read-only}.
+
+Floppies can be emulated with the @code{:floppy:} option:
+
+@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 
+qemu linux.img -fda fat:floppy:rw:/my_directory
+@end example
+
+What you should @emph{never} do:
+@itemize
+@item use non-ASCII filenames ;
+@item use "-snapshot" together with ":rw:" ;
+@item expect it to work when loadvm'ing ;
+@item write to the FAT directory on the host system while accessing it with the guest system.
+@end itemize
+
 @section Network emulation
 
-QEMU simulates up to 6 networks cards (NE2000 boards). Each card can
-be connected to a specific host network interface.
+QEMU can simulate several networks cards (NE2000 boards 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
+network stack can replace the TAP device to have a basic network
+connection.
 
-@subsection Using tun/tap network interface
+@subsection VLANs
 
-This is the standard way to emulate network. QEMU adds a virtual
-network device on your host (called @code{tun0}), and you can then
-configure it as if it was a real ethernet card.
+QEMU simulates several VLANs. A VLAN can be symbolised as a virtual
+connection between several network devices. These devices can be for
+example QEMU virtual Ethernet cards or virtual Host ethernet devices
+(TAP devices).
+
+@subsection Using TAP network interfaces
+
+This is the standard way to connect QEMU to a real network. QEMU adds
+a virtual network device on your host (called @code{tapN}), and you
+can then configure it as if it was a real ethernet card.
 
 As an example, you can download the @file{linux-test-xxx.tar.gz}
 archive and copy the script @file{qemu-ifup} in @file{/etc} and
 configure properly @code{sudo} so that the command @code{ifconfig}
 contained in @file{qemu-ifup} can be executed as root. You must verify
-that your host kernel supports the TUN/TAP network interfaces: the
+that your host kernel supports the TAP network interfaces: the
 device @file{/dev/net/tun} must be present.
 
 See @ref{direct_linux_boot} to have an example of network use with a
-Linux distribution.
+Linux distribution and @ref{sec_invocation} to have examples of
+command lines using the TAP network interfaces.
 
 @subsection Using the user mode network stack
 
-By using the option @option{-user-net} or if you have no tun/tap init
-script, QEMU uses a completely user mode network stack (you don't need
-root priviledge to use the virtual network). The virtual network
-configuration is the following:
+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). The virtual network configuration is the following:
 
 @example
 
-QEMU Virtual Machine    <------>  Firewall/DHCP server <-----> Internet
-     (10.0.2.x)            |          (10.0.2.2)
+         QEMU VLAN      <------>  Firewall/DHCP server <-----> Internet
+                           |          (10.0.2.2)
                            |
                            ---->  DNS server (10.0.2.3)
                            |     
@@ -662,7 +847,8 @@ QEMU Virtual Machine    <------>  Firewall/DHCP server <-----> Internet
 
 The QEMU VM behaves as if it was behind a firewall which blocks all
 incoming connections. You can use a DHCP client to automatically
-configure the network in the QEMU VM.
+configure the network in the QEMU VM. The DHCP server assign addresses
+to the hosts starting from 10.0.2.15.
 
 In order to check that the user mode network is working, you can ping
 the address 10.0.2.2 and verify that you got an address in the range
@@ -679,6 +865,12 @@ When using the @option{-redir} option, TCP or UDP connections can be
 redirected from the host to the guest. It allows for example to
 redirect X11, telnet or SSH connections.
 
+@subsection Connecting VLANs between QEMU instances
+
+Using the @option{-net socket} option, it is possible to make VLANs
+that span several QEMU instances. See @ref{sec_invocation} to have a
+basic example.
+
 @node direct_linux_boot
 @section Direct Linux Boot
 
@@ -825,6 +1017,80 @@ Lawton for the plex86 Project (@url{www.plex86.org}).
 
 @end enumerate
 
+@section USB emulation
+
+QEMU emulates a PCI UHCI USB controller and a 8 port USB hub connected
+to it. You can virtually plug to the hub virtual USB devices or real
+host USB devices (experimental, works only on Linux hosts).
+
+@subsection Using virtual USB devices
+
+A virtual USB mouse device is available for testing in QEMU.
+
+You can try it with the following monitor commands:
+
+@example
+# add the mouse device
+(qemu) usb_add mouse 
+
+# show the virtual USB devices plugged on the QEMU Virtual USB hub
+(qemu) info usb
+  Device 0.3, speed 12 Mb/s
+
+# after some time you can try to remove the mouse
+(qemu) usb_del 0.3
+@end example
+
+The option @option{-usbdevice} is similar to the monitor command
+@code{usb_add}.
+
+@subsection Using host USB devices on a Linux host
+
+WARNING: this is an experimental feature. QEMU will slow down when
+using it. USB devices requiring real time streaming (i.e. USB Video
+Cameras) are not supported yet.
+
+@enumerate
+@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}.
+
+@item Verify that @file{/proc/bus/usb} is working (most Linux distributions should enable it by default). You should see something like that:
+@example
+ls /proc/bus/usb
+001  devices  drivers
+@end example
+
+@item Since only root can access to the USB devices directly, you can either launch QEMU as root or change the permissions of the USB devices you want to use. For testing, the following suffices:
+@example
+chown -R myuid /proc/bus/usb
+@end example
+
+@item Launch QEMU and do in the monitor:
+@example 
+info usbhost
+  Device 1.2, speed 480 Mb/s
+    Class 00: USB device 1234:5678, USB DISK
+@end example
+You should see the list of the devices you can use (Never try to use
+hubs, it won't work).
+
+@item Add the device in QEMU by using:
+@example 
+usb_add host:1234:5678
+@end example
+
+Normally the guest OS should report that a new USB device is
+plugged. You can use the option @option{-usbdevice} to do the same.
+
+@item Now you can try to use the host USB device in QEMU.
+
+@end enumerate
+
+When relaunching QEMU, you may have to unplug and plug again the USB
+device to make it work again (this is a bug).
+
 @node gdb_usage
 @section GDB usage
 
@@ -952,7 +1218,13 @@ it takes host CPU cycles even when idle. You can install the utility
 from @url{http://www.vmware.com/software/dosidle210.zip} to solve this
 problem.
 
-@chapter QEMU PowerPC System emulator invocation
+@chapter QEMU System emulator for non PC targets
+
+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.
+
+@section QEMU PowerPC System emulator
 
 Use the executable @file{qemu-system-ppc} to simulate a complete PREP
 or PowerMac PowerPC system.
@@ -996,10 +1268,7 @@ PC compatible keyboard and mouse.
 @end itemize
 
 QEMU uses the Open Hack'Ware Open Firmware Compatible BIOS available at
-@url{http://site.voila.fr/jmayer/OpenHackWare/index.htm}.
-
-You can read the qemu PC system emulation chapter to have more
-informations about QEMU usage.
+@url{http://perso.magic.fr/l_indien/OpenHackWare/index.htm}.
 
 @c man begin OPTIONS
 
@@ -1007,9 +1276,6 @@ The following options are specific to the PowerPC emulation:
 
 @table @option
 
-@item -prep
-Simulate a PREP system (default is PowerMAC)
-
 @item -g WxH[xDEPTH]  
 
 Set the initial VGA graphic mode. The default is 800x600x15.
@@ -1020,9 +1286,9 @@ Set the initial VGA graphic mode. The default is 800x600x15.
 
 
 More information is available at
-@url{http://jocelyn.mayer.free.fr/qemu-ppc/}.
+@url{http://perso.magic.fr/l_indien/qemu-ppc/}.
 
-@chapter Sparc32 System emulator invocation
+@section Sparc32 System emulator invocation
 
 Use the executable @file{qemu-system-sparc} to simulate a JavaStation
 (sun4m architecture). The emulation is somewhat complete.
@@ -1071,7 +1337,7 @@ Set the initial TCX graphic mode. The default is 1024x768.
 
 @c man end 
 
-@chapter Sparc64 System emulator invocation
+@section Sparc64 System emulator invocation
 
 Use the executable @file{qemu-system-sparc64} to simulate a Sun4u machine.
 The emulator is not usable for anything yet.
@@ -1089,12 +1355,42 @@ Non Volatile RAM M48T59
 PC-compatible serial ports
 @end itemize
 
-@chapter MIPS System emulator invocation
+@section MIPS System emulator invocation
 
 Use the executable @file{qemu-system-mips} to simulate a MIPS machine.
-The emulator begins to launch a Linux kernel.
+The emulator is able to boot a Linux kernel and to run a Linux Debian
+installation from NFS. The following devices are emulated:
+
+@itemize @minus
+@item 
+MIPS R4K CPU
+@item
+PC style serial port
+@item
+NE2000 network card
+@end itemize
+
+More information is available in the QEMU mailing-list archive.
+
+@section ARM System emulator invocation
+
+Use the executable @file{qemu-system-arm} to simulate a ARM
+machine. The ARM Integrator/CP board is emulated with the following
+devices:
+
+@itemize @minus
+@item
+ARM1026E CPU
+@item
+Two PL011 UARTs
+@item 
+SMC 91c111 Ethernet adapter
+@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.
 
-@chapter QEMU User space emulator invocation
+@chapter QEMU Linux User space emulator 
 
 @section Quick Start
 
index 7181373..75b5003 100644 (file)
 .\" ========================================================================
 .\"
 .IX Title "QEMU-IMG 1"
-.TH QEMU-IMG 1 "2005-09-04" " " " "
+.TH QEMU-IMG 1 "2005-12-19" " " " "
 .SH "NAME"
 qemu\-img \- QEMU disk image utility
 .SH "SYNOPSIS"
index 774996e..cf6ed8a 100644 (file)
@@ -1,6 +1,6 @@
 <HTML>
 <HEAD>
-<!-- Created by texi2html 1.56k from qemu-tech.texi on 4 September 2005 -->
+<!-- Created by texi2html 1.56k from qemu-tech.texi on 19 December 2005 -->
 
 <TITLE>QEMU Internals</TITLE>
 </HEAD>
@@ -773,7 +773,7 @@ and host CPUs.
 <P>
 Example of usage of <CODE>libqemu</CODE> to emulate a user mode i386 CPU.
 <P><HR><P>
-This document was generated on 4 September 2005 using
+This document was generated on 19 December 2005 using
 <A HREF="http://wwwinfo.cern.ch/dis/texi2html/">texi2html</A>&nbsp;1.56k.
 </BODY>
 </HTML>
index 9d22629..ace3f1d 100644 (file)
 .\" ========================================================================
 .\"
 .IX Title "QEMU 1"
-.TH QEMU 1 "2005-09-04" " " " "
+.TH QEMU 1 "2005-12-19" " " " "
 .SH "NAME"
 qemu  \- QEMU System Emulator
 .SH "SYNOPSIS"
@@ -137,8 +137,8 @@ qemu  \- QEMU System Emulator
 usage: qemu [options] [disk_image]
 .SH "DESCRIPTION"
 .IX Header "DESCRIPTION"
-The \s-1QEMU\s0 System emulator simulates the
-following \s-1PC\s0 peripherals:
+The \s-1QEMU\s0 \s-1PC\s0 System emulator simulates the
+following peripherals:
 .IP "\-" 4
 i440FX host \s-1PCI\s0 bridge and \s-1PIIX3\s0 \s-1PCI\s0 to \s-1ISA\s0 bridge
 .IP "\-" 4
@@ -155,15 +155,31 @@ Floppy disk
 .IP "\-" 4
 Serial ports
 .IP "\-" 4
-Soundblaster 16 card
+Creative SoundBlaster 16 sound card
+.IP "\-" 4
+\&\s-1ENSONIQ\s0 AudioPCI \s-1ES1370\s0 sound card
+.IP "\-" 4
+Adlib(\s-1OPL2\s0) \- Yamaha \s-1YM3812\s0 compatible chip
+.IP "\-" 4
+\&\s-1PCI\s0 \s-1UHCI\s0 \s-1USB\s0 controller and a virtual \s-1USB\s0 hub.
+.PP
+\&\s-1SMP\s0 is supported with up to 255 CPUs.
+.PP
+Note that adlib is only available when \s-1QEMU\s0 was configured with
+\&\-enable\-adlib
 .PP
 \&\s-1QEMU\s0 uses the \s-1PC\s0 \s-1BIOS\s0 from the Bochs project and the Plex86/Bochs \s-1LGPL\s0
 \&\s-1VGA\s0 \s-1BIOS\s0.
+.PP
+\&\s-1QEMU\s0 uses \s-1YM3812\s0 emulation by Tatsuyuki Satoh.
 .SH "OPTIONS"
 .IX Header "OPTIONS"
 \&\fIdisk_image\fR is a raw hard disk image for \s-1IDE\s0 hard disk 0.
 .PP
 General options:
+.IP "\fB\-M machine\fR" 4
+.IX Item "-M machine"
+Select the emulated machine (\f(CW\*(C`\-M ?\*(C'\fR for list)
 .IP "\fB\-fda file\fR" 4
 .IX Item "-fda file"
 .PD 0
@@ -200,6 +216,10 @@ the write back by pressing \fBC\-a s\fR
 .IP "\fB\-m megs\fR" 4
 .IX Item "-m megs"
 Set virtual \s-1RAM\s0 size to \fImegs\fR megabytes. Default is 128 \s-1MB\s0.
+.IP "\fB\-smp n\fR" 4
+.IX Item "-smp n"
+Simulate an \s-1SMP\s0 system with \fIn\fR CPUs. On the \s-1PC\s0 target, up to 255
+CPUs are supported.
 .IP "\fB\-nographic\fR" 4
 .IX Item "-nographic"
 Normally, \s-1QEMU\s0 uses \s-1SDL\s0 to display the \s-1VGA\s0 output. With this option,
@@ -223,10 +243,21 @@ The available layouts are:
 .Ve
 .Sp
 The default is \f(CW\*(C`en\-us\*(C'\fR.
-.IP "\fB\-enable\-audio\fR" 4
-.IX Item "-enable-audio"
-The \s-1SB16\s0 emulation is disabled by default as it may give problems with
-Windows. You can enable it manually with this option.
+.IP "\fB\-audio\-help\fR" 4
+.IX Item "-audio-help"
+Will show the audio subsystem help: list of drivers, tunable
+parameters.
+.IP "\fB\-soundhw card1,card2,... or \-soundhw all\fR" 4
+.IX Item "-soundhw card1,card2,... or -soundhw all"
+Enable audio and selected sound hardware. Use ? to print all
+available sound hardware.
+.Sp
+.Vb 4
+\&        qemu -soundhw sb16,adlib hda
+\&        qemu -soundhw es1370 hda
+\&        qemu -soundhw all hda
+\&        qemu -soundhw ?
+.Ve
 .IP "\fB\-localtime\fR" 4
 .IX Item "-localtime"
 Set the real time clock to local time (the default is to \s-1UTC\s0
@@ -245,29 +276,105 @@ Use it when installing Windows 2000 to avoid a disk full bug. After
 Windows 2000 is installed, you no longer need this option (this option
 slows down the \s-1IDE\s0 transfers).
 .PP
+\&\s-1USB\s0 options:
+.IP "\fB\-usb\fR" 4
+.IX Item "-usb"
+Enable the \s-1USB\s0 driver (will be the default soon)
+.IP "\fB\-usbdevice devname\fR" 4
+.IX Item "-usbdevice devname"
+Add the \s-1USB\s0 device \fIdevname\fR. See the monitor command
+\&\f(CW\*(C`usb_add\*(C'\fR to have more information.
+.PP
 Network options:
-.IP "\fB\-n script\fR" 4
-.IX Item "-n script"
-Set \s-1TUN/TAP\s0 network init script [default=/etc/qemu\-ifup]. This script
-is launched to configure the host network interface (usually tun0)
-corresponding to the virtual \s-1NE2000\s0 card.
-.IP "\fB\-nics n\fR" 4
-.IX Item "-nics n"
-Simulate \fIn\fR network cards (the default is 1).
-.IP "\fB\-macaddr addr\fR" 4
-.IX Item "-macaddr addr"
-Set the mac address of the first interface (the format is
-aa:bb:cc:dd:ee:ff in hexa). The mac address is incremented for each
-new network interface.
-.IP "\fB\-tun\-fd fd\fR" 4
-.IX Item "-tun-fd fd"
-Assumes \fIfd\fR talks to a tap/tun host network interface and use
-it. Read <\fBhttp://bellard.org/qemu/tetrinet.html\fR> to have an
-example of its use.
-.IP "\fB\-user\-net\fR" 4
-.IX Item "-user-net"
-Use the user mode network stack. This is the default if no tun/tap
-network init script is found.
+.IP "\fB\-net nic[,vlan=n][,macaddr=addr]\fR" 4
+.IX Item "-net nic[,vlan=n][,macaddr=addr]"
+Create a new Network Interface Card and connect it to \s-1VLAN\s0 \fIn\fR (\fIn\fR
+= 0 is the default). The \s-1NIC\s0 is currently an \s-1NE2000\s0 on the \s-1PC\s0
+target. Optionally, the \s-1MAC\s0 address can be changed. If no
+\&\fB\-net\fR option is specified, a single \s-1NIC\s0 is created.
+.IP "\fB\-net user[,vlan=n]\fR" 4
+.IX Item "-net user[,vlan=n]"
+Use the user mode network stack which requires no administrator
+priviledge to run. This is the default if no \fB\-net\fR option is
+specified.
+.IP "\fB\-net tap[,vlan=n][,fd=h][,ifname=name][,script=file]\fR" 4
+.IX Item "-net tap[,vlan=n][,fd=h][,ifname=name][,script=file]"
+Connect the host \s-1TAP\s0 network interface \fIname\fR to \s-1VLAN\s0 \fIn\fR and
+use the network script \fIfile\fR to configure it. The default
+network script is \fI/etc/qemu\-ifup\fR. If \fIname\fR is not
+provided, the \s-1OS\s0 automatically provides one.  \fBfd=h\fR can be
+used to specify the handle of an already opened host \s-1TAP\s0 interface. Example:
+.Sp
+.Vb 1
+\&        qemu linux.img -net nic -net tap
+.Ve
+.Sp
+More complicated example (two NICs, each one connected to a \s-1TAP\s0 device)
+.Sp
+.Vb 2
+\&        qemu linux.img -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \e
+\&                       -net nic,vlan=1 -net tap,vlan=1,ifname=tap1
+.Ve
+.IP "\fB\-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\fR" 4
+.IX Item "-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]"
+Connect the \s-1VLAN\s0 \fIn\fR to a remote \s-1VLAN\s0 in another \s-1QEMU\s0 virtual
+machine using a \s-1TCP\s0 socket connection. If \fBlisten\fR is
+specified, \s-1QEMU\s0 waits for incoming connections on \fIport\fR
+(\fIhost\fR is optional). \fBconnect\fR is used to connect to
+another \s-1QEMU\s0 instance using the \fBlisten\fR option. \fBfd=h\fR
+specifies an already opened \s-1TCP\s0 socket.
+.Sp
+Example:
+.Sp
+.Vb 4
+\&        # launch a first QEMU instance
+\&        qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,listen=:1234
+\&        # connect the VLAN 0 of this instance to the VLAN 0 of the first instance
+\&        qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,connect=127.0.0.1:1234
+.Ve
+.IP "\fB\-net socket[,vlan=n][,fd=h][,mcast=maddr:port]\fR" 4
+.IX Item "-net socket[,vlan=n][,fd=h][,mcast=maddr:port]"
+Create a \s-1VLAN\s0 \fIn\fR shared with another \s-1QEMU\s0 virtual
+machines using a \s-1UDP\s0 multicast socket, effectively making a bus for 
+every \s-1QEMU\s0 with same multicast address \fImaddr\fR and \fIport\fR.
+\&\s-1NOTES:\s0
+.RS 4
+.IP "1." 4
+Several \s-1QEMU\s0 can be running on different hosts and share same bus (assuming 
+correct multicast setup for these hosts).
+.IP "2." 4
+mcast support is compatible with User Mode Linux (argument \fBeth\fR\fIN\fR\fB=mcast\fR), see
+<\fBhttp://user\-mode\-linux.sf.net\fR>.
+.IP "3.<Use \fBfd=h\fR to specify an already opened \s-1UDP\s0 multicast socket.>" 4
+.IX Item "3.<Use fd=h to specify an already opened UDP multicast socket.>"
+.RE
+.RS 4
+.Sp
+Example:
+.Sp
+.Vb 6
+\&        # launch one QEMU instance
+\&        qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=230.0.0.1:1234
+\&        # launch another QEMU instance on same "bus"
+\&        qemu linux.img -net nic,macaddr=52:54:00:12:34:57 -net socket,mcast=230.0.0.1:1234
+\&        # launch yet another QEMU instance on same "bus"
+\&        qemu linux.img -net nic,macaddr=52:54:00:12:34:58 -net socket,mcast=230.0.0.1:1234
+.Ve
+.Sp
+Example (User Mode Linux compat.):
+.Sp
+.Vb 4
+\&        # launch QEMU instance (note mcast address selected is UML's default)
+\&        qemu linux.img -net nic,macaddr=52:54:00:12:34:56 -net socket,mcast=239.192.168.1:1102
+\&        # launch UML
+\&        /path/to/linux ubd0=/path/to/root_fs eth0=mcast
+.Ve
+.RE
+.IP "\fB\-net none\fR" 4
+.IX Item "-net none"
+Indicate that no network devices should be configured. It is used to
+override the default configuration which is activated if no
+\&\fB\-net\fR options are provided.
 .IP "\fB\-tftp prefix\fR" 4
 .IX Item "-tftp prefix"
 When using the user mode network stack, activate a built-in \s-1TFTP\s0
@@ -325,12 +432,8 @@ the guest, use the following:
 .Sp
 Then when you use on the host \f(CW\*(C`telnet localhost 5555\*(C'\fR, you
 connect to the guest telnet server.
-.IP "\fB\-dummy\-net\fR" 4
-.IX Item "-dummy-net"
-Use the dummy network stack: no packet will be received by the network
-cards.
 .PP
-Linux boot specific. When using this options, you can use a given
+Linux boot specific: When using these options, you can use a given
 Linux kernel without installing it in the disk image. It can be useful
 for easier testing of various kernels.
 .IP "\fB\-kernel bzImage\fR" 4
@@ -361,10 +464,28 @@ Virtual console
 .el .IP "\f(CWnull\fR" 4
 .IX Item "null"
 void device
+.ie n .IP """/dev/XXX""" 4
+.el .IP "\f(CW/dev/XXX\fR" 4
+.IX Item "/dev/XXX"
+[Linux only] Use host tty, e.g. \fI/dev/ttyS0\fR. The host serial port
+parameters are set according to the emulated ones.
+.ie n .IP """/dev/parportN""" 4
+.el .IP "\f(CW/dev/parportN\fR" 4
+.IX Item "/dev/parportN"
+[Linux only, parallel port only] Use host parallel port
+\&\fIN\fR. Currently only \s-1SPP\s0 parallel port features can be used.
+.ie n .IP """file:filename""" 4
+.el .IP "\f(CWfile:filename\fR" 4
+.IX Item "file:filename"
+Write output to filename. No character can be read.
 .ie n .IP """stdio""" 4
 .el .IP "\f(CWstdio\fR" 4
 .IX Item "stdio"
 [Unix only] standard input/output
+.ie n .IP """pipe:filename""" 4
+.el .IP "\f(CWpipe:filename\fR" 4
+.IX Item "pipe:filename"
+[Unix only] name pipe \fIfilename\fR
 .RE
 .RS 4
 .Sp
@@ -374,6 +495,15 @@ non graphical mode.
 This option can be used several times to simulate up to 4 serials
 ports.
 .RE
+.IP "\fB\-parallel dev\fR" 4
+.IX Item "-parallel dev"
+Redirect the virtual parallel port to host device \fIdev\fR (same
+devices as the serial port). On Linux hosts, \fI/dev/parportN\fR can
+be used to use hardware devices connected on the corresponding host
+parallel port.
+.Sp
+This option can be used several times to simulate up to 3 parallel
+ports.
 .IP "\fB\-monitor dev\fR" 4
 .IX Item "-monitor dev"
 Redirect the monitor to host device \fIdev\fR (same devices as the
@@ -399,9 +529,6 @@ Force hard disk 0 physical geometry (1 <= \fIc\fR <= 16383, 1 <=
 translation mode (\fIt\fR=none, lba or auto). Usually \s-1QEMU\s0 can guess
 all thoses parameters. This option is useful for old MS-DOS disk
 images.
-.IP "\fB\-isa\fR" 4
-.IX Item "-isa"
-Simulate an ISA-only system (default is \s-1PCI\s0 system).
 .IP "\fB\-std\-vga\fR" 4
 .IX Item "-std-vga"
 Simulate a standard \s-1VGA\s0 card with Bochs \s-1VBE\s0 extensions (default is
@@ -459,9 +586,6 @@ Switch between console and monitor
 Send Ctrl-a
 .PP
 The following options are specific to the PowerPC emulation:
-.IP "\fB\-prep\fR" 4
-.IX Item "-prep"
-Simulate a \s-1PREP\s0 system (default is PowerMAC)
 .IP "\fB\-g WxH[xDEPTH]\fR" 4
 .IX Item "-g WxH[xDEPTH]"
 Set the initial \s-1VGA\s0 graphic mode. The default is 800x600x15.
index d43da88..9c7afd9 100644 (file)
@@ -55,11 +55,22 @@ static void sdl_resize(DisplayState *ds, int w, int h)
     flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
     if (gui_fullscreen)
         flags |= SDL_FULLSCREEN;
+
+ again:
     screen = SDL_SetVideoMode(w, h, 0, flags);
     if (!screen) {
         fprintf(stderr, "Could not open SDL display\n");
         exit(1);
     }
+    if (!screen->pixels && (flags & SDL_HWSURFACE) && (flags & SDL_FULLSCREEN)) {
+        flags &= ~SDL_HWSURFACE;
+        goto again;
+    }
+
+    if (!screen->pixels) {
+        fprintf(stderr, "Could not open SDL display\n");
+        exit(1);
+    }
     ds->data = screen->pixels;
     ds->linesize = screen->pitch;
     ds->depth = screen->format->BitsPerPixel;
diff --git a/qemu/softmmu_exec.h b/qemu/softmmu_exec.h
new file mode 100644 (file)
index 0000000..3b789ee
--- /dev/null
@@ -0,0 +1,65 @@
+/* Common softmmu definitions and inline routines.  */
+
+#define ldul_user ldl_user
+#define ldul_kernel ldl_kernel
+
+#define ACCESS_TYPE 0
+#define MEMSUFFIX _kernel
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+
+#define ACCESS_TYPE 1
+#define MEMSUFFIX _user
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+
+/* these access are slower, they must be as rare as possible */
+#define ACCESS_TYPE 2
+#define MEMSUFFIX _data
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+
+#define ldub(p) ldub_data(p)
+#define ldsb(p) ldsb_data(p)
+#define lduw(p) lduw_data(p)
+#define ldsw(p) ldsw_data(p)
+#define ldl(p) ldl_data(p)
+#define ldq(p) ldq_data(p)
+
+#define stb(p, v) stb_data(p, v)
+#define stw(p, v) stw_data(p, v)
+#define stl(p, v) stl_data(p, v)
+#define stq(p, v) stq_data(p, v)
index 0798cf5..e79592f 100644 (file)
 #define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM)
 #elif defined (TARGET_SPARC)
 #define CPU_MEM_INDEX ((env->psrs) == 0)
+#elif defined (TARGET_ARM)
+#define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
+#else
+#error unsupported CPU
 #endif
 #define MMUSUFFIX _mmu
 
 #define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM)
 #elif defined (TARGET_SPARC)
 #define CPU_MEM_INDEX ((env->psrs) == 0)
+#elif defined (TARGET_ARM)
+#define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
+#else
+#error unsupported CPU
 #endif
 #define MMUSUFFIX _cmmu
 
 #define RES_TYPE int
 #endif
 
+#if ACCESS_TYPE == 3
+#define ADDR_READ addr_code
+#else
+#define ADDR_READ addr_read
+#endif
 
 DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
                                                          int is_user);
@@ -93,6 +106,8 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE
 #if (DATA_SIZE <= 4) && (TARGET_LONG_BITS == 32) && defined(__i386__) && \
     (ACCESS_TYPE <= 1) && defined(ASM_SOFTMMU)
 
+#define CPU_TLB_ENTRY_BITS 4
+
 static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
 {
     int res;
@@ -112,7 +127,7 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
                   "movl %%eax, %0\n"
                   "jmp 2f\n"
                   "1:\n"
-                  "addl 4(%%edx), %%eax\n"
+                  "addl 12(%%edx), %%eax\n"
 #if DATA_SIZE == 1
                   "movzbl (%%eax), %0\n"
 #elif DATA_SIZE == 2
@@ -125,10 +140,10 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
                   "2:\n"
                   : "=r" (res)
                   : "r" (ptr), 
-                  "i" ((CPU_TLB_SIZE - 1) << 3), 
-                  "i" (TARGET_PAGE_BITS - 3), 
+                  "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_read[CPU_MEM_INDEX][0].address)),
+                  "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_read)),
                   "i" (CPU_MEM_INDEX),
                   "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX))
                   : "%eax", "%ecx", "%edx", "memory", "cc");
@@ -161,7 +176,7 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr)
 #endif
                   "jmp 2f\n"
                   "1:\n"
-                  "addl 4(%%edx), %%eax\n"
+                  "addl 12(%%edx), %%eax\n"
 #if DATA_SIZE == 1
                   "movsbl (%%eax), %0\n"
 #elif DATA_SIZE == 2
@@ -172,10 +187,10 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr)
                   "2:\n"
                   : "=r" (res)
                   : "r" (ptr), 
-                  "i" ((CPU_TLB_SIZE - 1) << 3), 
-                  "i" (TARGET_PAGE_BITS - 3), 
+                  "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_read[CPU_MEM_INDEX][0].address)),
+                  "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_read)),
                   "i" (CPU_MEM_INDEX),
                   "m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX))
                   : "%eax", "%ecx", "%edx", "memory", "cc");
@@ -208,7 +223,7 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE
                   "popl %%eax\n"
                   "jmp 2f\n"
                   "1:\n"
-                  "addl 4(%%edx), %%eax\n"
+                  "addl 8(%%edx), %%eax\n"
 #if DATA_SIZE == 1
                   "movb %b1, (%%eax)\n"
 #elif DATA_SIZE == 2
@@ -224,10 +239,10 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE
 /* NOTE: 'q' would be needed as constraint, but we could not use it
    with T1 ! */
                   "r" (v), 
-                  "i" ((CPU_TLB_SIZE - 1) << 3), 
-                  "i" (TARGET_PAGE_BITS - 3), 
+                  "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_write[CPU_MEM_INDEX][0].address)),
+                  "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_write)),
                   "i" (CPU_MEM_INDEX),
                   "m" (*(uint8_t *)&glue(glue(__st, SUFFIX), MMUSUFFIX))
                   : "%eax", "%ecx", "%edx", "memory", "cc");
@@ -248,11 +263,11 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
     addr = ptr;
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     is_user = CPU_MEM_INDEX;
-    if (__builtin_expect(env->tlb_read[is_user][index].address != 
+    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 {
-        physaddr = addr + env->tlb_read[is_user][index].addend;
+        physaddr = addr + env->tlb_table[is_user][index].addend;
         res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr);
     }
     return res;
@@ -269,17 +284,19 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr)
     addr = ptr;
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     is_user = CPU_MEM_INDEX;
-    if (__builtin_expect(env->tlb_read[is_user][index].address != 
+    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 {
-        physaddr = addr + env->tlb_read[is_user][index].addend;
+        physaddr = addr + env->tlb_table[is_user][index].addend;
         res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr);
     }
     return res;
 }
 #endif
 
+#if ACCESS_TYPE != 3
+
 /* generic store macro */
 
 static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v)
@@ -292,32 +309,36 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE
     addr = ptr;
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     is_user = CPU_MEM_INDEX;
-    if (__builtin_expect(env->tlb_write[is_user][index].address != 
+    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 {
-        physaddr = addr + env->tlb_write[is_user][index].addend;
+        physaddr = addr + env->tlb_table[is_user][index].addend;
         glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v);
     }
 }
 
-#endif
+#endif /* ACCESS_TYPE != 3 */
+
+#endif /* !asm */
+
+#if ACCESS_TYPE != 3
 
 #if DATA_SIZE == 8
-static inline double glue(ldfq, MEMSUFFIX)(target_ulong ptr)
+static inline float64 glue(ldfq, MEMSUFFIX)(target_ulong ptr)
 {
     union {
-        double d;
+        float64 d;
         uint64_t i;
     } u;
     u.i = glue(ldq, MEMSUFFIX)(ptr);
     return u.d;
 }
 
-static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, double v)
+static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, float64 v)
 {
     union {
-        double d;
+        float64 d;
         uint64_t i;
     } u;
     u.d = v;
@@ -326,20 +347,20 @@ static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, double v)
 #endif /* DATA_SIZE == 8 */
 
 #if DATA_SIZE == 4
-static inline float glue(ldfl, MEMSUFFIX)(target_ulong ptr)
+static inline float32 glue(ldfl, MEMSUFFIX)(target_ulong ptr)
 {
     union {
-        float f;
+        float32 f;
         uint32_t i;
     } u;
     u.i = glue(ldl, MEMSUFFIX)(ptr);
     return u.f;
 }
 
-static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float v)
+static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v)
 {
     union {
-        float f;
+        float32 f;
         uint32_t i;
     } u;
     u.f = v;
@@ -347,6 +368,8 @@ static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float v)
 }
 #endif /* DATA_SIZE == 4 */
 
+#endif /* ACCESS_TYPE != 3 */
+
 #undef RES_TYPE
 #undef DATA_TYPE
 #undef DATA_STYPE
@@ -355,3 +378,4 @@ static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float v)
 #undef DATA_SIZE
 #undef CPU_MEM_INDEX
 #undef MMUSUFFIX
+#undef ADDR_READ
index 558bb8b..9bae4f6 100644 (file)
 
 #ifdef SOFTMMU_CODE_ACCESS
 #define READ_ACCESS_TYPE 2
+#define ADDR_READ addr_code
 #else
 #define READ_ACCESS_TYPE 0
+#define ADDR_READ addr_read
 #endif
 
 static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, 
@@ -83,27 +85,40 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
     /* XXX: could done more in memory macro in a non portable way */
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
  redo:
-    tlb_addr = env->tlb_read[is_user][index].address;
+    tlb_addr = env->tlb_table[is_user][index].ADDR_READ;
     if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
-        physaddr = addr + env->tlb_read[is_user][index].addend;
+        physaddr = addr + env->tlb_table[is_user][index].addend;
         if (tlb_addr & ~TARGET_PAGE_MASK) {
             /* IO access */
             if ((addr & (DATA_SIZE - 1)) != 0)
                 goto do_unaligned_access;
             res = glue(io_read, SUFFIX)(physaddr, tlb_addr);
-        } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
+        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
             /* slow unaligned access (it spans two pages or IO) */
         do_unaligned_access:
             retaddr = GETPC();
+#ifdef ALIGNED_ONLY
+            do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr);
+#endif
             res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, 
                                                          is_user, retaddr);
         } else {
-            /* unaligned access in the same page */
+            /* unaligned/aligned access in the same page */
+#ifdef ALIGNED_ONLY
+            if ((addr & (DATA_SIZE - 1)) != 0) {
+                retaddr = GETPC();
+                do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr);
+            }
+#endif
             res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)(long)physaddr);
         }
     } else {
         /* the page is not in the TLB : fill it */
         retaddr = GETPC();
+#ifdef ALIGNED_ONLY
+        if ((addr & (DATA_SIZE - 1)) != 0)
+            do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr);
+#endif
         tlb_fill(addr, READ_ACCESS_TYPE, is_user, retaddr);
         goto redo;
     }
@@ -122,15 +137,15 @@ static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
 
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
  redo:
-    tlb_addr = env->tlb_read[is_user][index].address;
+    tlb_addr = env->tlb_table[is_user][index].ADDR_READ;
     if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
-        physaddr = addr + env->tlb_read[is_user][index].addend;
+        physaddr = addr + env->tlb_table[is_user][index].addend;
         if (tlb_addr & ~TARGET_PAGE_MASK) {
             /* IO access */
             if ((addr & (DATA_SIZE - 1)) != 0)
                 goto do_unaligned_access;
             res = glue(io_read, SUFFIX)(physaddr, tlb_addr);
-        } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
+        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
         do_unaligned_access:
             /* slow unaligned access (it spans two pages) */
             addr1 = addr & ~(DATA_SIZE - 1);
@@ -199,27 +214,40 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
     
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
  redo:
-    tlb_addr = env->tlb_write[is_user][index].address;
+    tlb_addr = env->tlb_table[is_user][index].addr_write;
     if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
-        physaddr = addr + env->tlb_write[is_user][index].addend;
+        physaddr = addr + env->tlb_table[is_user][index].addend;
         if (tlb_addr & ~TARGET_PAGE_MASK) {
             /* IO access */
             if ((addr & (DATA_SIZE - 1)) != 0)
                 goto do_unaligned_access;
             retaddr = GETPC();
             glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr);
-        } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
+        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
         do_unaligned_access:
             retaddr = GETPC();
+#ifdef ALIGNED_ONLY
+            do_unaligned_access(addr, 1, is_user, retaddr);
+#endif
             glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, 
                                                    is_user, retaddr);
         } else {
             /* aligned/unaligned access in the same page */
+#ifdef ALIGNED_ONLY
+            if ((addr & (DATA_SIZE - 1)) != 0) {
+                retaddr = GETPC();
+                do_unaligned_access(addr, 1, is_user, retaddr);
+            }
+#endif
             glue(glue(st, SUFFIX), _raw)((uint8_t *)(long)physaddr, val);
         }
     } else {
         /* the page is not in the TLB : fill it */
         retaddr = GETPC();
+#ifdef ALIGNED_ONLY
+        if ((addr & (DATA_SIZE - 1)) != 0)
+            do_unaligned_access(addr, 1, is_user, retaddr);
+#endif
         tlb_fill(addr, 1, is_user, retaddr);
         goto redo;
     }
@@ -237,15 +265,15 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
 
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
  redo:
-    tlb_addr = env->tlb_write[is_user][index].address;
+    tlb_addr = env->tlb_table[is_user][index].addr_write;
     if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
-        physaddr = addr + env->tlb_write[is_user][index].addend;
+        physaddr = addr + env->tlb_table[is_user][index].addend;
         if (tlb_addr & ~TARGET_PAGE_MASK) {
             /* IO access */
             if ((addr & (DATA_SIZE - 1)) != 0)
                 goto do_unaligned_access;
             glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr);
-        } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
+        } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
         do_unaligned_access:
             /* XXX: not efficient, but simple */
             for(i = 0;i < DATA_SIZE; i++) {
@@ -276,3 +304,4 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
 #undef SUFFIX
 #undef USUFFIX
 #undef DATA_SIZE
+#undef ADDR_READ
index 956597c..597dc8a 100644 (file)
@@ -2102,7 +2102,55 @@ lookup_value (table, value)
 \f
 /* Handle ASI's.  */
 
-static arg asi_table[] =
+static const arg asi_table_v8[] =
+{
+  { 0x00, "#ASI_M_RES00" },
+  { 0x01, "#ASI_M_UNA01" },
+  { 0x02, "#ASI_M_MXCC" },
+  { 0x03, "#ASI_M_FLUSH_PROBE" },
+  { 0x04, "#ASI_M_MMUREGS" },
+  { 0x05, "#ASI_M_TLBDIAG" },
+  { 0x06, "#ASI_M_DIAGS" },
+  { 0x07, "#ASI_M_IODIAG" },
+  { 0x08, "#ASI_M_USERTXT" },
+  { 0x09, "#ASI_M_KERNELTXT" },
+  { 0x0A, "#ASI_M_USERDATA" },
+  { 0x0B, "#ASI_M_KERNELDATA" },
+  { 0x0C, "#ASI_M_TXTC_TAG" },
+  { 0x0D, "#ASI_M_TXTC_DATA" },
+  { 0x0E, "#ASI_M_DATAC_TAG" },
+  { 0x0F, "#ASI_M_DATAC_DATA" },
+  { 0x10, "#ASI_M_FLUSH_PAGE" },
+  { 0x11, "#ASI_M_FLUSH_SEG" },
+  { 0x12, "#ASI_M_FLUSH_REGION" },
+  { 0x13, "#ASI_M_FLUSH_CTX" },
+  { 0x14, "#ASI_M_FLUSH_USER" },
+  { 0x17, "#ASI_M_BCOPY" },
+  { 0x18, "#ASI_M_IFLUSH_PAGE" },
+  { 0x19, "#ASI_M_IFLUSH_SEG" },
+  { 0x1A, "#ASI_M_IFLUSH_REGION" },
+  { 0x1B, "#ASI_M_IFLUSH_CTX" },
+  { 0x1C, "#ASI_M_IFLUSH_USER" },
+  { 0x1F, "#ASI_M_BFILL" },
+  { 0x20, "#ASI_M_BYPASS" },
+  { 0x29, "#ASI_M_FBMEM" },
+  { 0x2A, "#ASI_M_VMEUS" },
+  { 0x2B, "#ASI_M_VMEPS" },
+  { 0x2C, "#ASI_M_VMEUT" },
+  { 0x2D, "#ASI_M_VMEPT" },
+  { 0x2E, "#ASI_M_SBUS" },
+  { 0x2F, "#ASI_M_CTL" },
+  { 0x31, "#ASI_M_FLUSH_IWHOLE" },
+  { 0x36, "#ASI_M_IC_FLCLEAR" },
+  { 0x37, "#ASI_M_DC_FLCLEAR" },
+  { 0x39, "#ASI_M_DCDR" },
+  { 0x40, "#ASI_M_VIKING_TMP1" },
+  { 0x41, "#ASI_M_VIKING_TMP2" },
+  { 0x4c, "#ASI_M_ACTION" },
+  { 0, 0 }
+};
+
+static const arg asi_table_v9[] =
 {
   /* These are in the v9 architecture manual.  */
   /* The shorter versions appear first, they're here because Sun's as has them.
@@ -2142,22 +2190,18 @@ static arg asi_table[] =
   { 0, 0 }
 };
 
-/* Return the value for ASI NAME, or -1 if not found.  */
+/* Return the name for ASI value VALUE or NULL if not found.  */
 
-int
-sparc_encode_asi (name)
-     const char *name;
+static const char *
+sparc_decode_asi_v9 (int value)
 {
-  return lookup_name (asi_table, name);
+  return lookup_value (asi_table_v9, value);
 }
 
-/* Return the name for ASI value VALUE or NULL if not found.  */
-
-const char *
-sparc_decode_asi (value)
-     int value;
+static const char *
+sparc_decode_asi_v8 (int value)
 {
-  return lookup_value (asi_table, value);
+  return lookup_value (asi_table_v8, value);
 }
 \f
 /* Handle membar masks.  */
@@ -2841,7 +2885,12 @@ print_insn_sparc (memaddr, info)
 
                  case 'A':
                    {
-                     const char *name = sparc_decode_asi (X_ASI (insn));
+                     const char *name;
+
+                     if (info->mach == bfd_mach_sparc_v9)
+                       name = sparc_decode_asi_v9 (X_ASI (insn));
+                     else
+                       name = sparc_decode_asi_v8 (X_ASI (insn));
 
                      if (name)
                        (*info->fprintf_func) (stream, "%s", name);
index ef7469d..3b36839 100644 (file)
@@ -32,6 +32,8 @@
 #define EXCP_SWI             2   /* software interrupt */
 #define EXCP_PREFETCH_ABORT  3
 #define EXCP_DATA_ABORT      4
+#define EXCP_IRQ             5
+#define EXCP_FIQ             6
 
 /* We currently assume float and double are IEEE single and double
    precision respectively.
  */
 
 typedef struct CPUARMState {
+    /* Regs for current mode.  */
     uint32_t regs[16];
-    uint32_t cpsr;
+    /* Frequently accessed CPSR bits are stored separately for efficiently.
+       This contains all the other bits.  Use cpsr_{read,write} to accless
+       the whole CPSR.  */
+    uint32_t uncached_cpsr;
+    uint32_t spsr;
+
+    /* Banked registers.  */
+    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 */
@@ -53,29 +69,29 @@ typedef struct CPUARMState {
 
     int thumb; /* 0 = arm mode, 1 = thumb mode */
 
-    /* coprocessor 15 (MMU) status */
-    uint32_t cp15_6;
+    /* System control coprocessor (cp15) */
+    struct {
+        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 c5_insn; /* Fault status registers.  */
+        uint32_t c5_data;
+        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.  */
+    } cp15;
     
     /* exception/interrupt handling */
     jmp_buf jmp_env;
     int exception_index;
     int interrupt_request;
-    struct TranslationBlock *current_tb;
     int user_mode_only;
-    uint32_t address;
-
-    /* ICE debug support.  */
-    target_ulong breakpoints[MAX_BREAKPOINTS];
-    int nb_breakpoints;
-    int singlestep_enabled;
-
-    /* in order to avoid passing too many arguments to the memory
-       write helpers, we store some rarely used information in the CPU
-       context) */
-    unsigned long mem_write_pc; /* host pc at which the memory was
-                                   written */
-    unsigned long mem_write_vaddr; /* target virtual addr at which the
-                                      memory was written */
+    int halted;
+
     /* VFP coprocessor state.  */
     struct {
         float64 regs[16];
@@ -93,13 +109,16 @@ typedef struct CPUARMState {
         float_status fp_status;
     } vfp;
 
-    /* user data */
-    void *opaque;
+    CPU_COMMON
+
 } CPUARMState;
 
 CPUARMState *cpu_arm_init(void);
 int cpu_arm_exec(CPUARMState *s);
 void cpu_arm_close(CPUARMState *s);
+void do_interrupt(CPUARMState *);
+void switch_mode(CPUARMState *, int);
+
 /* 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.  */
@@ -107,7 +126,69 @@ struct siginfo;
 int cpu_arm_signal_handler(int host_signum, struct siginfo *info, 
                            void *puc);
 
+#define CPSR_M (0x1f)
+#define CPSR_T (1 << 5)
+#define CPSR_F (1 << 6)
+#define CPSR_I (1 << 7)
+#define CPSR_A (1 << 8)
+#define CPSR_E (1 << 9)
+#define CPSR_IT_2_7 (0xfc00)
+/* Bits 20-23 reserved.  */
+#define CPSR_J (1 << 24)
+#define CPSR_IT_0_1 (3 << 25)
+#define CPSR_Q (1 << 27)
+#define CPSR_NZCV (0xf << 28)
+
+#define CACHED_CPSR_BITS (CPSR_T | CPSR_Q | CPSR_NZCV)
+/* Return the current CPSR value.  */
+static inline uint32_t cpsr_read(CPUARMState *env)
+{
+    int ZF;
+    ZF = (env->NZF == 0);
+    return env->uncached_cpsr | (env->NZF & 0x80000000) | (ZF << 30) | 
+        (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27)
+        | (env->thumb << 5);
+}
+
+/* Set the CPSR.  Note that some bits of mask must be all-set or all-clear.  */
+static inline void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
+{
+    /* NOTE: N = 1 and Z = 1 cannot be stored currently */
+    if (mask & CPSR_NZCV) {
+        env->NZF = (val & 0xc0000000) ^ 0x40000000;
+        env->CF = (val >> 29) & 1;
+        env->VF = (val << 3) & 0x80000000;
+    }
+    if (mask & CPSR_Q)
+        env->QF = ((val & CPSR_Q) != 0);
+    if (mask & CPSR_T)
+        env->thumb = ((val & CPSR_T) != 0);
+
+    if ((env->uncached_cpsr ^ val) & mask & CPSR_M) {
+        switch_mode(env, val & CPSR_M);
+    }
+    mask &= ~CACHED_CPSR_BITS;
+    env->uncached_cpsr = (env->uncached_cpsr & ~mask) | (val & mask);
+}
+
+enum arm_cpu_mode {
+  ARM_CPU_MODE_USR = 0x10,
+  ARM_CPU_MODE_FIQ = 0x11,
+  ARM_CPU_MODE_IRQ = 0x12,
+  ARM_CPU_MODE_SVC = 0x13,
+  ARM_CPU_MODE_ABT = 0x17,
+  ARM_CPU_MODE_UND = 0x1b,
+  ARM_CPU_MODE_SYS = 0x1f
+};
+
+#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.  */
+#define TARGET_PAGE_BITS 10
+#endif
 #include "cpu-all.h"
 
 #endif
index 64fce71..2d2b99a 100644 (file)
@@ -34,16 +34,6 @@ register uint32_t T2 asm(AREG3);
 #include "cpu.h"
 #include "exec-all.h"
 
-/* Implemented CPSR bits.  */
-#define CACHED_CPSR_BITS 0xf8000000
-static inline int compute_cpsr(void)
-{
-    int ZF;
-    ZF = (env->NZF == 0);
-    return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | 
-        (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27);
-}
-
 static inline void env_to_regs(void)
 {
 }
@@ -55,10 +45,17 @@ static inline void regs_to_env(void)
 int cpu_arm_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
+
 /* In op_helper.c */
 
 void cpu_lock(void);
 void cpu_unlock(void);
+void helper_set_cp15(CPUState *, uint32_t, uint32_t);
+uint32_t helper_get_cp15(CPUState *, uint32_t);
+
 void cpu_loop_exit(void);
 
 void raise_exception(int);
@@ -75,3 +72,4 @@ void do_vfp_cmpes(void);
 void do_vfp_cmped(void);
 void do_vfp_set_fpscr(void);
 void do_vfp_get_fpscr(void);
+
diff --git a/qemu/target-arm/helper.c b/qemu/target-arm/helper.c
new file mode 100644 (file)
index 0000000..538e17a
--- /dev/null
@@ -0,0 +1,556 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+
+#if defined(CONFIG_USER_ONLY) 
+
+void do_interrupt (CPUState *env)
+{
+    env->exception_index = -1;
+}
+
+int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                              int is_user, int is_softmmu)
+{
+    if (rw == 2) {
+        env->exception_index = EXCP_PREFETCH_ABORT;
+        env->cp15.c6_insn = address;
+    } else {
+        env->exception_index = EXCP_DATA_ABORT;
+        env->cp15.c6_data = address;
+    }
+    return 1;
+}
+
+target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    return addr;
+}
+
+/* These should probably raise undefined insn exceptions.  */
+void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
+{
+    cpu_abort(env, "cp15 insn %08x\n", insn);
+}
+
+uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
+{
+    cpu_abort(env, "cp15 insn %08x\n", insn);
+    return 0;
+}
+
+void switch_mode(CPUState *env, int mode)
+{
+    if (mode != ARM_CPU_MODE_USR)
+        cpu_abort(env, "Tried to switch out of user mode\n");
+}
+
+#else
+
+/* Map CPU modes onto saved register banks.  */
+static inline int bank_number (int mode)
+{
+    switch (mode) {
+    case ARM_CPU_MODE_USR:
+    case ARM_CPU_MODE_SYS:
+        return 0;
+    case ARM_CPU_MODE_SVC:
+        return 1;
+    case ARM_CPU_MODE_ABT:
+        return 2;
+    case ARM_CPU_MODE_UND:
+        return 3;
+    case ARM_CPU_MODE_IRQ:
+        return 4;
+    case ARM_CPU_MODE_FIQ:
+        return 5;
+    }
+    cpu_abort(cpu_single_env, "Bad mode %x\n", mode);
+    return -1;
+}
+
+void switch_mode(CPUState *env, int mode)
+{
+    int old_mode;
+    int i;
+
+    old_mode = env->uncached_cpsr & CPSR_M;
+    if (mode == old_mode)
+        return;
+
+    if (old_mode == ARM_CPU_MODE_FIQ) {
+        memcpy (env->fiq_regs, env->regs + 8, 5 * sizeof(uint32_t));
+        memcpy (env->regs, env->usr_regs + 8, 5 * sizeof(uint32_t));
+    } else if (mode == ARM_CPU_MODE_FIQ) {
+        memcpy (env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
+        memcpy (env->regs, env->fiq_regs + 8, 5 * sizeof(uint32_t));
+    }
+
+    i = bank_number(old_mode);
+    env->banked_r13[i] = env->regs[13];
+    env->banked_r14[i] = env->regs[14];
+    env->banked_spsr[i] = env->spsr;
+
+    i = bank_number(mode);
+    env->regs[13] = env->banked_r13[i];
+    env->regs[14] = env->banked_r14[i];
+    env->spsr = env->banked_spsr[i];
+}
+
+/* Handle a CPU exception.  */
+void do_interrupt(CPUARMState *env)
+{
+    uint32_t addr;
+    uint32_t mask;
+    int new_mode;
+    uint32_t offset;
+
+    /* TODO: Vectored interrupt controller.  */
+    switch (env->exception_index) {
+    case EXCP_UDEF:
+        new_mode = ARM_CPU_MODE_UND;
+        addr = 0x04;
+        mask = CPSR_I;
+        if (env->thumb)
+            offset = 2;
+        else
+            offset = 4;
+        break;
+    case EXCP_SWI:
+        new_mode = ARM_CPU_MODE_SVC;
+        addr = 0x08;
+        mask = CPSR_I;
+        /* The PC already points to the next instructon.  */
+        offset = 0;
+        break;
+    case EXCP_PREFETCH_ABORT:
+        new_mode = ARM_CPU_MODE_ABT;
+        addr = 0x0c;
+        mask = CPSR_A | CPSR_I;
+        offset = 4;
+        break;
+    case EXCP_DATA_ABORT:
+        new_mode = ARM_CPU_MODE_ABT;
+        addr = 0x10;
+        mask = CPSR_A | CPSR_I;
+        offset = 8;
+        break;
+    case EXCP_IRQ:
+        new_mode = ARM_CPU_MODE_IRQ;
+        addr = 0x18;
+        /* Disable IRQ and imprecise data aborts.  */
+        mask = CPSR_A | CPSR_I;
+        offset = 4;
+        break;
+    case EXCP_FIQ:
+        new_mode = ARM_CPU_MODE_FIQ;
+        addr = 0x1c;
+        /* Disable FIQ, IRQ and imprecise data aborts.  */
+        mask = CPSR_A | CPSR_I | CPSR_F;
+        offset = 4;
+        break;
+    default:
+        cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index);
+        return; /* Never happens.  Keep compiler happy.  */
+    }
+    /* High vectors.  */
+    if (env->cp15.c1_sys & (1 << 13)) {
+        addr += 0xffff0000;
+    }
+    switch_mode (env, new_mode);
+    env->spsr = cpsr_read(env);
+    /* Switch to the new mode, and switch to Arm mode.  */
+    /* ??? Thumb interrupt handlers not implemented.  */
+    env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
+    env->uncached_cpsr |= mask;
+    env->thumb = 0;
+    env->regs[14] = env->regs[15] + offset;
+    env->regs[15] = addr;
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+
+/* Check section/page access permissions.
+   Returns the page protection flags, or zero if the access is not
+   permitted.  */
+static inline int check_ap(CPUState *env, int ap, int domain, int access_type,
+                           int is_user)
+{
+  if (domain == 3)
+    return PAGE_READ | PAGE_WRITE;
+
+  switch (ap) {
+  case 0:
+      if (access_type != 1)
+          return 0;
+      switch ((env->cp15.c1_sys >> 8) & 3) {
+      case 1:
+          return is_user ? 0 : PAGE_READ;
+      case 2:
+          return PAGE_READ;
+      default:
+          return 0;
+      }
+  case 1:
+      return is_user ? 0 : PAGE_READ | PAGE_WRITE;
+  case 2:
+      if (is_user)
+          return (access_type == 1) ? 0 : PAGE_READ;
+      else
+          return PAGE_READ | PAGE_WRITE;
+  case 3:
+      return PAGE_READ | PAGE_WRITE;
+  default:
+      abort();
+  }
+}
+
+static int get_phys_addr(CPUState *env, uint32_t address, int access_type,
+                         int is_user, uint32_t *phys_ptr, int *prot)
+{
+    int code;
+    uint32_t table;
+    uint32_t desc;
+    int type;
+    int ap;
+    int domain;
+    uint32_t phys_addr;
+
+    /* Fast Context Switch Extension.  */
+    if (address < 0x02000000)
+        address += env->cp15.c13_fcse;
+
+    if ((env->cp15.c1_sys & 1) == 0) {
+        /* MMU diusabled.  */
+        *phys_ptr = address;
+        *prot = PAGE_READ | PAGE_WRITE;
+    } else {
+        /* Pagetable walk.  */
+        /* Lookup l1 descriptor.  */
+        table = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc);
+        desc = ldl_phys(table);
+        type = (desc & 3);
+        domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3;
+        if (type == 0) {
+            /* Secton translation fault.  */
+            code = 5;
+            goto do_fault;
+        }
+        if (domain == 0 || domain == 2) {
+            if (type == 2)
+                code = 9; /* Section domain fault.  */
+            else
+                code = 11; /* Page domain fault.  */
+            goto do_fault;
+        }
+        if (type == 2) {
+            /* 1Mb section.  */
+            phys_addr = (desc & 0xfff00000) | (address & 0x000fffff);
+            ap = (desc >> 10) & 3;
+            code = 13;
+        } else {
+            /* Lookup l2 entry.  */
+            table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc);
+            desc = ldl_phys(table);
+            switch (desc & 3) {
+            case 0: /* Page translation fault.  */
+                code = 7;
+                goto do_fault;
+            case 1: /* 64k page.  */
+                phys_addr = (desc & 0xffff0000) | (address & 0xffff);
+                ap = (desc >> (4 + ((address >> 13) & 6))) & 3;
+                break;
+            case 2: /* 4k page.  */
+                phys_addr = (desc & 0xfffff000) | (address & 0xfff);
+                ap = (desc >> (4 + ((address >> 13) & 6))) & 3;
+                break;
+            case 3: /* 1k page.  */
+                if (type == 1) {
+                    /* Page translation fault.  */
+                    code = 7;
+                    goto do_fault;
+                }
+                phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
+                ap = (desc >> 4) & 3;
+                break;
+            default:
+                /* Never happens, but compiler isn't smart enough to tell.  */
+                abort();
+            }
+            code = 15;
+        }
+        *prot = check_ap(env, ap, domain, access_type, is_user);
+        if (!*prot) {
+            /* Access permission fault.  */
+            goto do_fault;
+        }
+        *phys_ptr = phys_addr;
+    }
+    return 0;
+do_fault:
+    return code | (domain << 4);
+}
+
+int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address,
+                              int access_type, int is_user, int is_softmmu)
+{
+    uint32_t phys_addr;
+    int prot;
+    int ret;
+
+    ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot);
+    if (ret == 0) {
+        /* Map a single [sub]page.  */
+        phys_addr &= ~(uint32_t)0x3ff;
+        address &= ~(uint32_t)0x3ff;
+        return tlb_set_page (env, address, phys_addr, prot, is_user,
+                             is_softmmu);
+    }
+
+    if (access_type == 2) {
+        env->cp15.c5_insn = ret;
+        env->cp15.c6_insn = address;
+        env->exception_index = EXCP_PREFETCH_ABORT;
+    } else {
+        env->cp15.c5_data = ret;
+        env->cp15.c6_data = address;
+        env->exception_index = EXCP_DATA_ABORT;
+    }
+    return 1;
+}
+
+target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    uint32_t phys_addr;
+    int prot;
+    int ret;
+
+    ret = get_phys_addr(env, addr, 0, 0, &phys_addr, &prot);
+
+    if (ret != 0)
+        return -1;
+
+    return phys_addr;
+}
+
+void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
+{
+    uint32_t op2;
+
+    op2 = (insn >> 5) & 7;
+    switch ((insn >> 16) & 0xf) {
+    case 0: /* ID codes.  */
+        goto bad_reg;
+    case 1: /* System configuration.  */
+        switch (op2) {
+        case 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 2:
+            env->cp15.c1_coproc = val;
+            /* ??? Is this safe when called from within a TB?  */
+            tb_flush(env);
+        default:
+            goto bad_reg;
+        }
+        break;
+    case 2: /* MMU Page table control.  */
+        env->cp15.c2 = val;
+        break;
+    case 3: /* MMU Domain access control.  */
+        env->cp15.c3 = val;
+        break;
+    case 4: /* Reserved.  */
+        goto bad_reg;
+    case 5: /* MMU Fault status.  */
+        switch (op2) {
+        case 0:
+            env->cp15.c5_data = val;
+            break;
+        case 1:
+            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;
+        }
+        break;
+    case 7: /* Cache control.  */
+        /* No cache, so nothing to do.  */
+        break;
+    case 8: /* MMU TLB control.  */
+        switch (op2) {
+        case 0: /* Invalidate all.  */
+            tlb_flush(env, 0);
+            break;
+        case 1: /* Invalidate single TLB entry.  */
+#if 0
+            /* ??? This is wrong for large pages and sections.  */
+            /* As an ugly hack to make linux work we always flush a 4K
+               pages.  */
+            val &= 0xfffff000;
+            tlb_flush_page(env, val);
+            tlb_flush_page(env, val + 0x400);
+            tlb_flush_page(env, val + 0x800);
+            tlb_flush_page(env, val + 0xc00);
+#else
+            tlb_flush(env, 1);
+#endif
+            break;
+        default:
+            goto bad_reg;
+        }
+        break;
+    case 9: /* 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 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:
+            env->cp15.c9_data = val;
+            break;
+        case 1:
+            env->cp15.c9_insn = val;
+            break;
+        default:
+            goto bad_reg;
+        }
+        break;
+    case 14: /* Reserved.  */
+        goto bad_reg;
+    case 15: /* Implementation specific.  */
+        /* ??? Internal registers not implemented.  */
+        break;
+    }
+    return;
+bad_reg:
+    /* ??? For debugging only.  Should raise illegal instruction exception.  */
+    cpu_abort(env, "Unimplemented cp15 register read\n");
+}
+
+uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
+{
+    uint32_t op2;
+
+    op2 = (insn >> 5) & 7;
+    switch ((insn >> 16) & 0xf) {
+    case 0: /* ID codes.  */
+        switch (op2) {
+        default: /* Device ID.  */
+            return 0x4106a262;
+        case 1: /* Cache Type.  */
+            return 0x1dd20d2;
+        case 2: /* TCM status.  */
+            return 0;
+        }
+    case 1: /* System configuration.  */
+        switch (op2) {
+        case 0: /* Control register.  */
+            return env->cp15.c1_sys;
+        case 1: /* Auxiliary control register.  */
+            return 1;
+        case 2: /* Coprocessor access register.  */
+            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.  */
+        return env->cp15.c3;
+    case 4: /* Reserved.  */
+        goto bad_reg;
+    case 5: /* MMU Fault status.  */
+        switch (op2) {
+        case 0:
+            return env->cp15.c5_data;
+        case 1:
+            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:
+            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
+           the N flag.  Oh well.  */
+        env->NZF = 0;
+        return 0;
+    case 8: /* MMU TLB control.  */
+        goto bad_reg;
+    case 9: /* Cache lockdown.  */
+        switch (op2) {
+        case 0:
+            return env->cp15.c9_data;
+        case 1:
+            return env->cp15.c9_insn;
+        default:
+            goto bad_reg;
+        }
+    case 10: /* MMU TLB lockdown.  */
+        /* ??? TLB lockdown not implemented.  */
+        return 0;
+    case 11: /* TCM DMA control.  */
+    case 12: /* Reserved.  */
+        goto bad_reg;
+    case 13: /* Process ID.  */
+        switch (op2) {
+        case 0:
+            return env->cp15.c13_fcse;
+        case 1:
+            return env->cp15.c13_context;
+        default:
+            goto bad_reg;
+        }
+    case 14: /* Reserved.  */
+        goto bad_reg;
+    case 15: /* Implementation specific.  */
+        /* ??? Internal registers not implemented.  */
+        return 0;
+    }
+bad_reg:
+    /* ??? For debugging only.  Should raise illegal instruction exception.  */
+    cpu_abort(env, "Unimplemented cp15 register read\n");
+    return 0;
+}
+
+#endif
index 8a82def..35419a1 100644 (file)
@@ -101,6 +101,11 @@ void OPPROTO op_movl_T0_im(void)
     T0 = PARAM1;
 }
 
+void OPPROTO op_movl_T0_T1(void)
+{
+    T0 = T1;
+}
+
 void OPPROTO op_movl_T1_im(void)
 {
     T1 = PARAM1;
@@ -346,14 +351,14 @@ void OPPROTO op_test_le(void)
     FORCE_RET();
 }
 
-void OPPROTO op_jmp0(void)
+void OPPROTO op_goto_tb0(void)
 {
-    JUMP_TB(op_jmp0, PARAM1, 0, PARAM2);
+    GOTO_TB(op_goto_tb0, PARAM1, 0);
 }
 
-void OPPROTO op_jmp1(void)
+void OPPROTO op_goto_tb1(void)
 {
-    JUMP_TB(op_jmp1, PARAM1, 1, PARAM2);
+    GOTO_TB(op_goto_tb1, PARAM1, 1);
 }
 
 void OPPROTO op_exit_tb(void)
@@ -361,20 +366,27 @@ void OPPROTO op_exit_tb(void)
     EXIT_TB();
 }
 
-void OPPROTO op_movl_T0_psr(void)
+void OPPROTO op_movl_T0_cpsr(void)
+{
+    T0 = cpsr_read(env);
+    FORCE_RET();
+}
+
+void OPPROTO op_movl_T0_spsr(void)
+{
+    T0 = env->spsr;
+}
+
+void OPPROTO op_movl_spsr_T0(void)
 {
-    T0 = compute_cpsr();
+    uint32_t mask = PARAM1;
+    env->spsr = (env->spsr & ~mask) | (T0 & mask);
 }
 
-/* NOTE: N = 1 and Z = 1 cannot be stored currently */
-void OPPROTO op_movl_psr_T0(void)
+void OPPROTO op_movl_cpsr_T0(void)
 {
-    unsigned int psr;
-    psr = T0;
-    env->CF = (psr >> 29) & 1;
-    env->NZF = (psr & 0xc0000000) ^ 0x40000000;
-    env->VF = (psr << 3) & 0x80000000;
-    /* for user mode we do not update other state info */
+    cpsr_write(env, T0, PARAM1);
+    FORCE_RET();
 }
 
 void OPPROTO op_mul_T0_T1(void)
@@ -433,67 +445,15 @@ void OPPROTO op_logicq_cc(void)
 
 /* memory access */
 
-void OPPROTO op_ldub_T0_T1(void)
-{
-    T0 = ldub((void *)T1);
-}
-
-void OPPROTO op_ldsb_T0_T1(void)
-{
-    T0 = ldsb((void *)T1);
-}
-
-void OPPROTO op_lduw_T0_T1(void)
-{
-    T0 = lduw((void *)T1);
-}
-
-void OPPROTO op_ldsw_T0_T1(void)
-{
-    T0 = ldsw((void *)T1);
-}
-
-void OPPROTO op_ldl_T0_T1(void)
-{
-    T0 = ldl((void *)T1);
-}
-
-void OPPROTO op_stb_T0_T1(void)
-{
-    stb((void *)T1, T0);
-}
-
-void OPPROTO op_stw_T0_T1(void)
-{
-    stw((void *)T1, T0);
-}
-
-void OPPROTO op_stl_T0_T1(void)
-{
-    stl((void *)T1, T0);
-}
-
-void OPPROTO op_swpb_T0_T1(void)
-{
-    int tmp;
-
-    cpu_lock();
-    tmp = ldub((void *)T1);
-    stb((void *)T1, T0);
-    T0 = tmp;
-    cpu_unlock();
-}
+#define MEMSUFFIX _raw
+#include "op_mem.h"
 
-void OPPROTO op_swpl_T0_T1(void)
-{
-    int tmp;
-
-    cpu_lock();
-    tmp = ldl((void *)T1);
-    stl((void *)T1, T0);
-    T0 = tmp;
-    cpu_unlock();
-}
+#if !defined(CONFIG_USER_ONLY)
+#define MEMSUFFIX _user
+#include "op_mem.h"
+#define MEMSUFFIX _kernel
+#include "op_mem.h"
+#endif
 
 /* shifts */
 
@@ -744,17 +704,48 @@ void OPPROTO op_sarl_T0_im(void)
     T0 = (int32_t)T0 >> PARAM1;
 }
 
-/* 16->32 Sign extend */
-void OPPROTO op_sxl_T0(void)
+/* Sign/zero extend */
+void OPPROTO op_sxth_T0(void)
 {
   T0 = (int16_t)T0;
 }
 
-void OPPROTO op_sxl_T1(void)
+void OPPROTO op_sxth_T1(void)
 {
   T1 = (int16_t)T1;
 }
 
+void OPPROTO op_sxtb_T1(void)
+{
+    T1 = (int8_t)T1;
+}
+
+void OPPROTO op_uxtb_T1(void)
+{
+    T1 = (uint8_t)T1;
+}
+
+void OPPROTO op_uxth_T1(void)
+{
+    T1 = (uint16_t)T1;
+}
+
+void OPPROTO op_sxtb16_T1(void)
+{
+    uint32_t res;
+    res = (uint16_t)(int8_t)T1;
+    res |= (uint32_t)(int8_t)(T1 >> 16) << 16;
+    T1 = res;
+}
+
+void OPPROTO op_uxtb16_T1(void)
+{
+    uint32_t res;
+    res = (uint16_t)(uint8_t)T1;
+    res |= (uint32_t)(uint8_t)(T1 >> 16) << 16;
+    T1 = res;
+}
+
 #define SIGNBIT (uint32_t)0x80000000
 /* saturating arithmetic  */
 void OPPROTO op_addl_T0_T1_setq(void)
@@ -887,6 +878,13 @@ void OPPROTO op_debug(void)
     cpu_loop_exit();
 }
 
+void OPPROTO op_wfi(void)
+{
+    env->exception_index = EXCP_HLT;
+    env->halted = 1;
+    cpu_loop_exit();
+}
+
 /* VFP support.  We follow the convention used for VFP instrunctions:
    Single precition routines have a "s" suffix, double precision a
    "d" suffix.  */
@@ -1128,23 +1126,52 @@ void OPPROTO op_vfp_mdrr(void)
     FT0d = u.d;
 }
 
-/* Floating point load/store.  Address is in T1 */
-void OPPROTO op_vfp_lds(void)
+/* Copy the most significant bit to T0 to all bits of T1.  */
+void OPPROTO op_signbit_T1_T0(void)
+{
+    T1 = (int32_t)T0 >> 31;
+}
+
+void OPPROTO op_movl_cp15_T0(void)
 {
-    FT0s = ldfl((void *)T1);
+    helper_set_cp15(env, PARAM1, T0);
+    FORCE_RET();
 }
 
-void OPPROTO op_vfp_ldd(void)
+void OPPROTO op_movl_T0_cp15(void)
 {
-    FT0d = ldfq((void *)T1);
+    T0 = helper_get_cp15(env, PARAM1);
+    FORCE_RET();
 }
 
-void OPPROTO op_vfp_sts(void)
+/* Access to user mode registers from privileged modes.  */
+void OPPROTO op_movl_T0_user(void)
 {
-    stfl((void *)T1, FT0s);
+    int regno = PARAM1;
+    if (regno == 13) {
+        T0 = env->banked_r13[0];
+    } else if (regno == 14) {
+        T0 = env->banked_r14[0];
+    } else if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
+        T0 = env->usr_regs[regno - 8];
+    } else {
+        T0 = env->regs[regno];
+    }
+    FORCE_RET();
 }
 
-void OPPROTO op_vfp_std(void)
+
+void OPPROTO op_movl_user_T0(void)
 {
-    stfq((void *)T1, FT0d);
+    int regno = PARAM1;
+    if (regno == 13) {
+        env->banked_r13[0] = T0;
+    } else if (regno == 14) {
+        env->banked_r14[0] = T0;
+    } else if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
+        env->usr_regs[regno - 8] = T0;
+    } else {
+        env->regs[regno] = T0;
+    }
+    FORCE_RET();
 }
index a0cddb6..c075b53 100644 (file)
@@ -172,3 +172,54 @@ void do_vfp_get_fpscr(void)
     i = get_float_exception_flags(&env->vfp.fp_status);
     T0 |= vfp_exceptbits_from_host(i);
 }
+
+#if !defined(CONFIG_USER_ONLY)
+
+#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_arm_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);
+            }
+        }
+        raise_exception(env->exception_index);
+    }
+    env = saved_env;
+}
+
+#endif
diff --git a/qemu/target-arm/op_mem.h b/qemu/target-arm/op_mem.h
new file mode 100644 (file)
index 0000000..29fd85b
--- /dev/null
@@ -0,0 +1,70 @@
+/* ARM memory operations.  */
+
+/* Load from address T1 into T0.  */
+#define MEM_LD_OP(name) \
+void OPPROTO glue(op_ld##name,MEMSUFFIX)(void) \
+{ \
+    T0 = glue(ld##name,MEMSUFFIX)(T1); \
+    FORCE_RET(); \
+}
+
+MEM_LD_OP(ub)
+MEM_LD_OP(sb)
+MEM_LD_OP(uw)
+MEM_LD_OP(sw)
+MEM_LD_OP(l)
+
+#undef MEM_LD_OP
+
+/* Store T0 to address T1.  */
+#define MEM_ST_OP(name) \
+void OPPROTO glue(op_st##name,MEMSUFFIX)(void) \
+{ \
+    glue(st##name,MEMSUFFIX)(T1, T0); \
+    FORCE_RET(); \
+}
+
+MEM_ST_OP(b)
+MEM_ST_OP(w)
+MEM_ST_OP(l)
+
+#undef MEM_ST_OP
+
+/* Swap T0 with memory at address T1.  */
+/* ??? Is this exception safe?  */
+#define MEM_SWP_OP(name, lname) \
+void OPPROTO glue(op_swp##name,MEMSUFFIX)(void) \
+{ \
+    uint32_t tmp; \
+    cpu_lock(); \
+    tmp = glue(ld##lname,MEMSUFFIX)(T1); \
+    glue(st##name,MEMSUFFIX)(T1, T0); \
+    T0 = tmp; \
+    cpu_unlock(); \
+    FORCE_RET(); \
+}
+
+MEM_SWP_OP(b, ub)
+MEM_SWP_OP(l, l)
+
+#undef MEM_SWP_OP
+
+/* Floating point load/store.  Address is in T1 */
+#define VFP_MEM_OP(p, w) \
+void OPPROTO glue(op_vfp_ld##p,MEMSUFFIX)(void) \
+{ \
+    FT0##p = glue(ldf##w,MEMSUFFIX)(T1); \
+    FORCE_RET(); \
+} \
+void OPPROTO glue(op_vfp_st##p,MEMSUFFIX)(void) \
+{ \
+    glue(stf##w,MEMSUFFIX)(T1, FT0##p); \
+    FORCE_RET(); \
+}
+
+VFP_MEM_OP(s,l)
+VFP_MEM_OP(d,q)
+
+#undef VFP_MEM_OP
+
+#undef MEMSUFFIX
index c3e8fe8..089fbf2 100644 (file)
 #include "exec-all.h"
 #include "disas.h"
 
+#define ENABLE_ARCH_5J  0
+#define ENABLE_ARCH_6   1
+#define ENABLE_ARCH_6T2 1
+
+#define ARCH(x) if (!ENABLE_ARCH_##x) goto illegal_op;
+
 /* internal defines */
 typedef struct DisasContext {
     target_ulong pc;
@@ -39,10 +45,25 @@ typedef struct DisasContext {
     struct TranslationBlock *tb;
     int singlestep_enabled;
     int thumb;
+#if !defined(CONFIG_USER_ONLY)
+    int user;
+#endif
 } DisasContext;
 
+#if defined(CONFIG_USER_ONLY)
+#define IS_USER(s) 1
+#else
+#define IS_USER(s) (s->user)
+#endif
+
 #define DISAS_JUMP_NEXT 4
 
+#ifdef USE_DIRECT_JUMP
+#define TBPARAM(x)
+#else
+#define TBPARAM(x) (long)(x)
+#endif
+
 /* XXX: move that elsewhere */
 static uint16_t *gen_opc_ptr;
 static uint32_t *gen_opparam_ptr;
@@ -264,6 +285,18 @@ static inline void gen_bx(DisasContext *s)
   gen_op_bx_T0();
 }
 
+
+#if defined(CONFIG_USER_ONLY)
+#define gen_ldst(name, s) gen_op_##name##_raw()
+#else
+#define gen_ldst(name, s) do { \
+    if (IS_USER(s)) \
+        gen_op_##name##_user(); \
+    else \
+        gen_op_##name##_kernel(); \
+    } while (0)
+#endif
+
 static inline void gen_movl_TN_reg(DisasContext *s, int reg, int t)
 {
     int val;
@@ -313,6 +346,14 @@ static inline void gen_movl_reg_T1(DisasContext *s, int reg)
     gen_movl_reg_TN(s, reg, 1);
 }
 
+/* Force a TB lookup after an instruction that changes the CPU state.  */
+static inline void gen_lookup_tb(DisasContext *s)
+{
+    gen_op_movl_T0_im(s->pc);
+    gen_movl_reg_T0(s, 15);
+    s->is_jmp = DISAS_UPDATE;
+}
+
 static inline void gen_add_data_offset(DisasContext *s, unsigned int insn)
 {
     int val, rm, shift, shiftop;
@@ -389,11 +430,25 @@ VFP_OP(toui)
 VFP_OP(touiz)
 VFP_OP(tosi)
 VFP_OP(tosiz)
-VFP_OP(ld)
-VFP_OP(st)
 
 #undef VFP_OP
 
+static inline void gen_vfp_ld(DisasContext *s, int dp)
+{
+    if (dp)
+        gen_ldst(vfp_ldd, s);
+    else
+        gen_ldst(vfp_lds, s);
+}
+
+static inline void gen_vfp_st(DisasContext *s, int dp)
+{
+    if (dp)
+        gen_ldst(vfp_std, s);
+    else
+        gen_ldst(vfp_sts, s);
+}
+
 static inline long
 vfp_reg_offset (int dp, int reg)
 {
@@ -431,6 +486,39 @@ static inline void gen_mov_vreg_F0(int dp, int reg)
         gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg));
 }
 
+/* Disassemble system coprocessor (cp15) instruction.  Return nonzero if
+   instruction is not defined.  */
+static int disas_cp15_insn(DisasContext *s, uint32_t insn)
+{
+    uint32_t rd;
+
+    /* ??? Some cp15 registers are accessible from userspace.  */
+    if (IS_USER(s)) {
+        return 1;
+    }
+    if ((insn & 0x0fff0fff) == 0x0e070f90
+        || (insn & 0x0fff0fff) == 0x0e070f58) {
+        /* Wait for interrupt.  */
+        gen_op_movl_T0_im((long)s->pc);
+        gen_op_movl_reg_TN[0][15]();
+        gen_op_wfi();
+        s->is_jmp = DISAS_JUMP;
+        return 0;
+    }
+    rd = (insn >> 12) & 0xf;
+    if (insn & (1 << 20)) {
+        gen_op_movl_T0_cp15(insn);
+        /* If the destination register is r15 then sets condition codes.  */
+        if (rd != 15)
+            gen_movl_reg_T0(s, rd);
+    } else {
+        gen_movl_T0_reg(s, rd);
+        gen_op_movl_cp15_T0(insn);
+    }
+    gen_lookup_tb(s);
+    return 0;
+}
+
 /* Disassemble a VFP instruction.  Returns nonzero if an error occured
    (ie. an undefined instruction).  */
 static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
@@ -493,8 +581,8 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                         gen_op_vfp_mrs();
                     }
                     if (rd == 15) {
-                        /* This will only set the 4 flag bits */
-                        gen_op_movl_psr_T0();
+                        /* Set the 4 flag bits in the CPSR.  */
+                        gen_op_movl_cpsr_T0(0xf0000000);
                     } else
                         gen_movl_reg_T0(s, rd);
                 } else {
@@ -510,9 +598,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                             gen_op_vfp_movl_fpscr_T0();
                             /* This could change vector settings, so jump to
                                the next instuction.  */
-                            gen_op_movl_T0_im(s->pc);
-                            gen_movl_reg_T0(s, 15);
-                            s->is_jmp = DISAS_UPDATE;
+                            gen_lookup_tb(s);
                             break;
                         default:
                             return 1;
@@ -842,11 +928,11 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     offset = -offset;
                 gen_op_addl_T1_im(offset);
                 if (insn & (1 << 20)) {
-                    gen_vfp_ld(dp);
+                    gen_vfp_ld(s, dp);
                     gen_mov_vreg_F0(dp, rd);
                 } else {
                     gen_mov_F0_vreg(dp, rd);
-                    gen_vfp_st(dp);
+                    gen_vfp_st(s, dp);
                 }
             } else {
                 /* load/store multiple */
@@ -865,12 +951,12 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
                 for (i = 0; i < n; i++) {
                     if (insn & (1 << 20)) {
                         /* load */
-                        gen_vfp_ld(dp);
+                        gen_vfp_ld(s, dp);
                         gen_mov_vreg_F0(dp, rd + i);
                     } else {
                         /* store */
                         gen_mov_F0_vreg(dp, rd + i);
-                        gen_vfp_st(dp);
+                        gen_vfp_st(s, dp);
                     }
                     gen_op_addl_T1_im(offset);
                 }
@@ -897,6 +983,28 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
     return 0;
 }
 
+static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
+{
+    TranslationBlock *tb;
+
+    tb = s->tb;
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
+        if (n == 0)
+            gen_op_goto_tb0(TBPARAM(tb));
+        else
+            gen_op_goto_tb1(TBPARAM(tb));
+        gen_op_movl_T0_im(dest);
+        gen_op_movl_r15_T0();
+        gen_op_movl_T0_im((long)tb + n);
+        gen_op_exit_tb();
+    } else {
+        gen_op_movl_T0_im(dest);
+        gen_op_movl_r15_T0();
+        gen_op_movl_T0_0();
+        gen_op_exit_tb();
+    }
+}
+
 static inline void gen_jmp (DisasContext *s, uint32_t dest)
 {
     if (__builtin_expect(s->singlestep_enabled, 0)) {
@@ -906,16 +1014,73 @@ static inline void gen_jmp (DisasContext *s, uint32_t dest)
         gen_op_movl_T0_im(dest);
         gen_bx(s);
     } else {
-        gen_op_jmp0((long)s->tb, dest);
+        gen_goto_tb(s, 0, dest);
         s->is_jmp = DISAS_TB_JUMP;
     }
 }
 
+static inline void gen_mulxy(int x, int y)
+{
+    if (x)
+        gen_op_sarl_T0_im(16);
+    else
+        gen_op_sxth_T0();
+    if (y)
+        gen_op_sarl_T1_im(16);
+    else
+        gen_op_sxth_T1();
+    gen_op_mul_T0_T1();
+}
+
+/* Return the mask of PSR bits set by a MSR instruction.  */
+static uint32_t msr_mask(DisasContext *s, int flags) {
+    uint32_t mask;
+
+    mask = 0;
+    if (flags & (1 << 0))
+        mask |= 0xff;
+    if (flags & (1 << 1))
+        mask |= 0xff00;
+    if (flags & (1 << 2))
+        mask |= 0xff0000;
+    if (flags & (1 << 3))
+        mask |= 0xff000000;
+    /* Mask out undefined bits and state bits.  */
+    mask &= 0xf89f03df;
+    /* Mask out privileged bits.  */
+    if (IS_USER(s))
+        mask &= 0xf80f0200;
+    return mask;
+}
+
+/* Returns nonzero if access to the PSR is not permitted.  */
+static int gen_set_psr_T0(DisasContext *s, uint32_t mask, int spsr)
+{
+    if (spsr) {
+        /* ??? This is also undefined in system mode.  */
+        if (IS_USER(s))
+            return 1;
+        gen_op_movl_spsr_T0(mask);
+    } else {
+        gen_op_movl_cpsr_T0(mask);
+    }
+    gen_lookup_tb(s);
+    return 0;
+}
+
+static void gen_exception_return(DisasContext *s)
+{
+    gen_op_movl_reg_TN[0][15]();
+    gen_op_movl_T0_spsr();
+    gen_op_movl_cpsr_T0(0xffffffff);
+    s->is_jmp = DISAS_UPDATE;
+}
+
 static void disas_arm_insn(CPUState * env, DisasContext *s)
 {
     unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
     
-    insn = ldl(s->pc);
+    insn = ldl_code(s->pc);
     s->pc += 4;
     
     cond = insn >> 28;
@@ -943,6 +1108,15 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             /* Coprocessor double register transfer.  */
         } else if ((insn & 0x0f000010) == 0x0e000010) {
             /* Additional coprocessor register transfer.  */
+        } else if ((insn & 0x0ff10010) == 0x01000000) {
+            /* cps (privileged) */
+        } else if ((insn & 0x0ffffdff) == 0x01010000) {
+            /* setend */
+            if (insn & (1 << 9)) {
+                /* BE8 mode not implemented.  */
+                goto illegal_op;
+            }
+            return;
         }
         goto illegal_op;
     }
@@ -956,7 +1130,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         //s->is_jmp = DISAS_JUMP_NEXT;
     }
     if ((insn & 0x0f900000) == 0x03000000) {
-        if ((insn & 0x0ff0f000) != 0x0360f000)
+        if ((insn & 0x0fb0f000) != 0x0320f000)
             goto illegal_op;
         /* CPSR = immediate */
         val = insn & 0xff;
@@ -964,8 +1138,9 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         if (shift)
             val = (val >> shift) | (val << (32 - shift));
         gen_op_movl_T0_im(val);
-        if (insn & (1 << 19))
-            gen_op_movl_psr_T0();
+        if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf),
+                           (insn & (1 << 22)) != 0))
+            goto illegal_op;
     } else if ((insn & 0x0f900000) == 0x01000000
                && (insn & 0x00000090) != 0x00000090) {
         /* miscellaneous instructions */
@@ -974,19 +1149,22 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         rm = insn & 0xf;
         switch (sh) {
         case 0x0: /* move program status register */
-            if (op1 & 2) {
-                /* SPSR not accessible in user mode */
-                goto illegal_op;
-            }
             if (op1 & 1) {
-                /* CPSR = reg */
+                /* PSR = reg */
                 gen_movl_T0_reg(s, rm);
-                if (insn & (1 << 19))
-                    gen_op_movl_psr_T0();
+                if (gen_set_psr_T0(s, msr_mask(s, (insn >> 16) & 0xf),
+                                   (op1 & 2) != 0))
+                    goto illegal_op;
             } else {
                 /* reg = CPSR */
                 rd = (insn >> 12) & 0xf;
-                gen_op_movl_T0_psr();
+                if (op1 & 2) {
+                    if (IS_USER(s))
+                        goto illegal_op;
+                    gen_op_movl_T0_spsr();
+                } else {
+                    gen_op_movl_T0_cpsr();
+                }
                 gen_movl_reg_T0(s, rd);
             }
             break;
@@ -1005,6 +1183,16 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 goto illegal_op;
             }
             break;
+        case 0x2:
+            if (op1 == 1) {
+                ARCH(5J); /* bxj */
+                /* Trivial implementation equivalent to bx.  */
+                gen_movl_T0_reg(s, rm);
+                gen_bx(s);
+            } else {
+                goto illegal_op;
+            }
+            break;
         case 0x3:
             if (op1 != 1)
               goto illegal_op;
@@ -1043,7 +1231,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 if (sh & 4)
                     gen_op_sarl_T1_im(16);
                 else
-                    gen_op_sxl_T1();
+                    gen_op_sxth_T1();
                 gen_op_imulw_T0_T1();
                 if ((sh & 2) == 0) {
                     gen_movl_T1_reg(s, rn);
@@ -1053,22 +1241,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             } else {
                 /* 16 * 16 */
                 gen_movl_T0_reg(s, rm);
-                if (sh & 2)
-                    gen_op_sarl_T0_im(16);
-                else
-                    gen_op_sxl_T0();
                 gen_movl_T1_reg(s, rs);
-                if (sh & 4)
-                    gen_op_sarl_T1_im(16);
-                else
-                    gen_op_sxl_T1();
+                gen_mulxy(sh & 2, sh & 4);
                 if (op1 == 2) {
-                    gen_op_imull_T0_T1();
+                    gen_op_signbit_T1_T0();
                     gen_op_addq_T0_T1(rn, rd);
                     gen_movl_reg_T0(s, rn);
                     gen_movl_reg_T1(s, rd);
                 } else {
-                    gen_op_mul_T0_T1();
                     if (op1 == 0) {
                         gen_movl_T1_reg(s, rn);
                         gen_op_addl_T0_T1_setq();
@@ -1148,11 +1328,19 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 gen_op_logic_T0_cc();
             break;
         case 0x02:
-            if (set_cc)
+            if (set_cc && rd == 15) {
+                /* SUBS r15, ... is used for exception return.  */
+                if (IS_USER(s))
+                    goto illegal_op;
                 gen_op_subl_T0_T1_cc();
-            else
-                gen_op_subl_T0_T1();
-            gen_movl_reg_T0(s, rd);
+                gen_exception_return(s);
+            } else {
+                if (set_cc)
+                    gen_op_subl_T0_T1_cc();
+                else
+                    gen_op_subl_T0_T1();
+                gen_movl_reg_T0(s, rd);
+            }
             break;
         case 0x03:
             if (set_cc)
@@ -1218,9 +1406,17 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 gen_op_logic_T0_cc();
             break;
         case 0x0d:
-            gen_movl_reg_T1(s, rd);
-            if (logic_cc)
-                gen_op_logic_T1_cc();
+            if (logic_cc && rd == 15) {
+                /* MOVS r15, ... is used for exception return.  */
+                if (IS_USER(s))
+                    goto illegal_op;
+                gen_op_movl_T0_T1();
+                gen_exception_return(s);
+            } else {
+                gen_movl_reg_T1(s, rd);
+                if (logic_cc)
+                    gen_op_logic_T1_cc();
+            }
             break;
         case 0x0e:
             gen_op_bicl_T0_T1();
@@ -1273,6 +1469,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                         if (insn & (1 << 21)) /* mult accumulate */
                             gen_op_addq_T0_T1(rn, rd);
                         if (!(insn & (1 << 23))) { /* double accumulate */
+                            ARCH(6);
                             gen_op_addq_lo_T0_T1(rn);
                             gen_op_addq_lo_T0_T1(rd);
                         }
@@ -1294,9 +1491,9 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                         gen_movl_T0_reg(s, rm);
                         gen_movl_T1_reg(s, rn);
                         if (insn & (1 << 22)) {
-                            gen_op_swpb_T0_T1();
+                            gen_ldst(swpb, s);
                         } else {
-                            gen_op_swpl_T0_T1();
+                            gen_ldst(swpl, s);
                         }
                         gen_movl_reg_T0(s, rd);
                     }
@@ -1312,14 +1509,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     /* load */
                     switch(sh) {
                     case 1:
-                        gen_op_lduw_T0_T1();
+                        gen_ldst(lduw, s);
                         break;
                     case 2:
-                        gen_op_ldsb_T0_T1();
+                        gen_ldst(ldsb, s);
                         break;
                     default:
                     case 3:
-                        gen_op_ldsw_T0_T1();
+                        gen_ldst(ldsw, s);
                         break;
                     }
                     gen_movl_reg_T0(s, rd);
@@ -1328,18 +1525,18 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     if (sh & 1) {
                         /* store */
                         gen_movl_T0_reg(s, rd);
-                        gen_op_stl_T0_T1();
+                        gen_ldst(stl, s);
                         gen_op_addl_T1_im(4);
                         gen_movl_T0_reg(s, rd + 1);
-                        gen_op_stl_T0_T1();
+                        gen_ldst(stl, s);
                         if ((insn & (1 << 24)) || (insn & (1 << 20)))
                             gen_op_addl_T1_im(-4);
                     } else {
                         /* load */
-                        gen_op_ldl_T0_T1();
+                        gen_ldst(ldl, s);
                         gen_movl_reg_T0(s, rd);
                         gen_op_addl_T1_im(4);
-                        gen_op_ldl_T0_T1();
+                        gen_ldst(ldl, s);
                         gen_movl_reg_T0(s, rd + 1);
                         if ((insn & (1 << 24)) || (insn & (1 << 20)))
                             gen_op_addl_T1_im(-4);
@@ -1347,7 +1544,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 } else {
                     /* store */
                     gen_movl_T0_reg(s, rd);
-                    gen_op_stw_T0_T1();
+                    gen_ldst(stw, s);
                 }
                 if (!(insn & (1 << 24))) {
                     gen_add_datah_offset(s, insn);
@@ -1365,14 +1562,29 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             rn = (insn >> 16) & 0xf;
             rd = (insn >> 12) & 0xf;
             gen_movl_T1_reg(s, rn);
+            i = (IS_USER(s) || (insn & 0x01200000) == 0x00200000);
             if (insn & (1 << 24))
                 gen_add_data_offset(s, insn);
             if (insn & (1 << 20)) {
                 /* load */
+#if defined(CONFIG_USER_ONLY)
                 if (insn & (1 << 22))
-                    gen_op_ldub_T0_T1();
+                    gen_op_ldub_raw();
                 else
-                    gen_op_ldl_T0_T1();
+                    gen_op_ldl_raw();
+#else
+                if (insn & (1 << 22)) {
+                    if (i)
+                        gen_op_ldub_user();
+                    else
+                        gen_op_ldub_kernel();
+                } else {
+                    if (i)
+                        gen_op_ldl_user();
+                    else
+                        gen_op_ldl_kernel();
+                }
+#endif
                 if (rd == 15)
                     gen_bx(s);
                 else
@@ -1380,10 +1592,24 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
             } else {
                 /* store */
                 gen_movl_T0_reg(s, rd);
+#if defined(CONFIG_USER_ONLY)
                 if (insn & (1 << 22))
-                    gen_op_stb_T0_T1();
+                    gen_op_stb_raw();
                 else
-                    gen_op_stl_T0_T1();
+                    gen_op_stl_raw();
+#else
+                if (insn & (1 << 22)) {
+                    if (i)
+                        gen_op_stb_user();
+                    else
+                        gen_op_stb_kernel();
+                } else {
+                    if (i)
+                        gen_op_stl_user();
+                    else
+                        gen_op_stl_kernel();
+                }
+#endif
             }
             if (!(insn & (1 << 24))) {
                 gen_add_data_offset(s, insn);
@@ -1395,11 +1621,17 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
         case 0x08:
         case 0x09:
             {
-                int j, n;
+                int j, n, user;
                 /* load/store multiple words */
                 /* XXX: store correct base if write back */
-                if (insn & (1 << 22))
-                    goto illegal_op; /* only usable in supervisor mode */
+                user = 0;
+                if (insn & (1 << 22)) {
+                    if (IS_USER(s))
+                        goto illegal_op; /* only usable in supervisor mode */
+
+                    if ((insn & (1 << 15)) == 0)
+                        user = 1;
+                }
                 rn = (insn >> 16) & 0xf;
                 gen_movl_T1_reg(s, rn);
                 
@@ -1432,21 +1664,26 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     if (insn & (1 << i)) {
                         if (insn & (1 << 20)) {
                             /* load */
-                            gen_op_ldl_T0_T1();
-                            if (i == 15)
+                            gen_ldst(ldl, s);
+                            if (i == 15) {
                                 gen_bx(s);
-                            else
+                            } else if (user) {
+                                gen_op_movl_user_T0(i);
+                            } else {
                                 gen_movl_reg_T0(s, i);
+                            }
                         } else {
                             /* store */
                             if (i == 15) {
                                 /* special case: r15 = PC + 12 */
                                 val = (long)s->pc + 8;
                                 gen_op_movl_TN_im[0](val);
+                            } else if (user) {
+                                gen_op_movl_T0_user(i);
                             } else {
                                 gen_movl_T0_reg(s, i);
                             }
-                            gen_op_stl_T0_T1();
+                            gen_ldst(stl, s);
                         }
                         j++;
                         /* no need to add after the last transfer */
@@ -1475,6 +1712,12 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     }
                     gen_movl_reg_T1(s, rn);
                 }
+                if ((insn & (1 << 22)) && !user) {
+                    /* Restore CPSR from SPSR.  */
+                    gen_op_movl_T0_spsr();
+                    gen_op_movl_cpsr_T0(0xffffffff);
+                    s->is_jmp = DISAS_UPDATE;
+                }
             }
             break;
         case 0xa:
@@ -1504,6 +1747,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                 if (disas_vfp_insn (env, s, insn))
                     goto illegal_op;
                 break;
+            case 15:
+                if (disas_cp15_insn (s, insn))
+                    goto illegal_op;
+                break;
             default:
                 /* unknown coprocessor.  */
                 goto illegal_op;
@@ -1533,9 +1780,9 @@ static void disas_thumb_insn(DisasContext *s)
     int32_t offset;
     int i;
 
-    insn = lduw(s->pc);
+    insn = lduw_code(s->pc);
     s->pc += 2;
-    
+
     switch (insn >> 12) {
     case 0: case 1:
         rd = insn & 7;
@@ -1600,7 +1847,7 @@ static void disas_thumb_insn(DisasContext *s)
             val = s->pc + 2 + ((insn & 0xff) * 4);
             val &= ~(uint32_t)2;
             gen_op_movl_T1_im(val);
-            gen_op_ldl_T0_T1();
+            gen_ldst(ldl, s);
             gen_movl_reg_T0(s, rd);
             break;
         }
@@ -1743,28 +1990,28 @@ static void disas_thumb_insn(DisasContext *s)
 
         switch (op) {
         case 0: /* str */
-            gen_op_stl_T0_T1();
+            gen_ldst(stl, s);
             break;
         case 1: /* strh */
-            gen_op_stw_T0_T1();
+            gen_ldst(stw, s);
             break;
         case 2: /* strb */
-            gen_op_stb_T0_T1();
+            gen_ldst(stb, s);
             break;
         case 3: /* ldrsb */
-            gen_op_ldsb_T0_T1();
+            gen_ldst(ldsb, s);
             break;
         case 4: /* ldr */
-            gen_op_ldl_T0_T1();
+            gen_ldst(ldl, s);
             break;
         case 5: /* ldrh */
-            gen_op_lduw_T0_T1();
+            gen_ldst(lduw, s);
             break;
         case 6: /* ldrb */
-            gen_op_ldub_T0_T1();
+            gen_ldst(ldub, s);
             break;
         case 7: /* ldrsh */
-            gen_op_ldsw_T0_T1();
+            gen_ldst(ldsw, s);
             break;
         }
         if (op >= 3) /* load */
@@ -1782,12 +2029,12 @@ static void disas_thumb_insn(DisasContext *s)
 
         if (insn & (1 << 11)) {
             /* load */
-            gen_op_ldl_T0_T1();
+            gen_ldst(ldl, s);
             gen_movl_reg_T0(s, rd);
         } else {
             /* store */
             gen_movl_T0_reg(s, rd);
-            gen_op_stl_T0_T1();
+            gen_ldst(stl, s);
         }
         break;
 
@@ -1802,12 +2049,12 @@ static void disas_thumb_insn(DisasContext *s)
 
         if (insn & (1 << 11)) {
             /* load */
-            gen_op_ldub_T0_T1();
+            gen_ldst(ldub, s);
             gen_movl_reg_T0(s, rd);
         } else {
             /* store */
             gen_movl_T0_reg(s, rd);
-            gen_op_stb_T0_T1();
+            gen_ldst(stb, s);
         }
         break;
 
@@ -1822,12 +2069,12 @@ static void disas_thumb_insn(DisasContext *s)
 
         if (insn & (1 << 11)) {
             /* load */
-            gen_op_lduw_T0_T1();
+            gen_ldst(lduw, s);
             gen_movl_reg_T0(s, rd);
         } else {
             /* store */
             gen_movl_T0_reg(s, rd);
-            gen_op_stw_T0_T1();
+            gen_ldst(stw, s);
         }
         break;
 
@@ -1841,12 +2088,12 @@ static void disas_thumb_insn(DisasContext *s)
 
         if (insn & (1 << 11)) {
             /* load */
-            gen_op_ldl_T0_T1();
+            gen_ldst(ldl, s);
             gen_movl_reg_T0(s, rd);
         } else {
             /* store */
             gen_movl_T0_reg(s, rd);
-            gen_op_stl_T0_T1();
+            gen_ldst(stl, s);
         }
         break;
 
@@ -1901,12 +2148,12 @@ static void disas_thumb_insn(DisasContext *s)
                 if (insn & (1 << i)) {
                     if (insn & (1 << 11)) {
                         /* pop */
-                        gen_op_ldl_T0_T1();
+                        gen_ldst(ldl, s);
                         gen_movl_reg_T0(s, i);
                     } else {
                         /* push */
                         gen_movl_T0_reg(s, i);
-                        gen_op_stl_T0_T1();
+                        gen_ldst(stl, s);
                     }
                     /* advance to the next address.  */
                     gen_op_addl_T1_T2();
@@ -1915,13 +2162,13 @@ static void disas_thumb_insn(DisasContext *s)
             if (insn & (1 << 8)) {
                 if (insn & (1 << 11)) {
                     /* pop pc */
-                    gen_op_ldl_T0_T1();
+                    gen_ldst(ldl, s);
                     /* don't set the pc until the rest of the instruction
                        has completed */
                 } else {
                     /* push lr */
                     gen_movl_T0_reg(s, 14);
-                    gen_op_stl_T0_T1();
+                    gen_ldst(stl, s);
                 }
                 gen_op_addl_T1_T2();
             }
@@ -1950,19 +2197,20 @@ static void disas_thumb_insn(DisasContext *s)
             if (insn & (1 << i)) {
                 if (insn & (1 << 11)) {
                     /* load */
-                    gen_op_ldl_T0_T1();
+                    gen_ldst(ldl, s);
                     gen_movl_reg_T0(s, i);
                 } else {
                     /* store */
                     gen_movl_T0_reg(s, i);
-                    gen_op_stl_T0_T1();
+                    gen_ldst(stl, s);
                 }
                 /* advance to the next address */
                 gen_op_addl_T1_T2();
             }
         }
         /* Base register writeback.  */
-        gen_movl_reg_T1(s, rn);
+        if ((insn & (1 << rn)) == 0)
+            gen_movl_reg_T1(s, rn);
         break;
 
     case 13:
@@ -2008,7 +2256,7 @@ static void disas_thumb_insn(DisasContext *s)
     case 15:
         /* branch and link [and switch to arm] */
         offset = ((int32_t)insn << 21) >> 10;
-        insn = lduw(s->pc);
+        insn = lduw_code(s->pc);
         offset |= insn & 0x7ff;
 
         val = (uint32_t)s->pc + 2;
@@ -2016,7 +2264,7 @@ static void disas_thumb_insn(DisasContext *s)
         gen_movl_reg_T1(s, 14);
         
         val += offset << 1;
-        if (insn & (1 << 11)) {
+        if (insn & (1 << 12)) {
             /* bl */
             gen_jmp(s, val);
         } else {
@@ -2045,6 +2293,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
     uint16_t *gen_opc_end;
     int j, lj;
     target_ulong pc_start;
+    uint32_t next_page_start;
     
     /* generate intermediate code */
     pc_start = tb->pc;
@@ -2060,6 +2309,10 @@ static inline int gen_intermediate_code_internal(CPUState *env,
     dc->singlestep_enabled = env->singlestep_enabled;
     dc->condjmp = 0;
     dc->thumb = env->thumb;
+#if !defined(CONFIG_USER_ONLY)
+    dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR;
+#endif
+    next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
     nb_gen_labels = 0;
     lj = -1;
     do {
@@ -2096,12 +2349,13 @@ static inline int gen_intermediate_code_internal(CPUState *env,
         }
         /* 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
+         * ensures prefech aborts occur at the right place.  */
     } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
              !env->singlestep_enabled &&
-             (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
-    /* It this stage dc->condjmp will only be set when the skipped
-     * instruction was a conditional branch, and teh PC has already been
+             dc->pc < next_page_start);
+    /* At this stage dc->condjmp will only be set when the skipped
+     * instruction was a conditional branch, and the PC has already been
      * written.  */
     if (__builtin_expect(env->singlestep_enabled, 0)) {
         /* Make sure the pc is updated, and raise a debug exception.  */
@@ -2118,7 +2372,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
     } else {
         switch(dc->is_jmp) {
         case DISAS_NEXT:
-            gen_op_jmp1((long)dc->tb, (long)dc->pc);
+            gen_goto_tb(dc, 1, dc->pc);
             break;
         default:
         case DISAS_JUMP:
@@ -2133,7 +2387,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
         }
         if (dc->condjmp) {
             gen_set_label(dc->condlabel);
-            gen_op_jmp1((long)dc->tb, (long)dc->pc);
+            gen_goto_tb(dc, 1, dc->pc);
             dc->condjmp = 0;
         }
     }
@@ -2152,8 +2406,15 @@ static inline int gen_intermediate_code_internal(CPUState *env,
         }
     }
 #endif
-    if (!search_pc)
+    if (search_pc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j)
+            gen_opc_instr_start[lj++] = 0;
+        tb->size = 0;
+    } else {
         tb->size = dc->pc - pc_start;
+    }
     return 0;
 }
 
@@ -2167,17 +2428,27 @@ int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
     return gen_intermediate_code_internal(env, tb, 1);
 }
 
+void cpu_reset(CPUARMState *env)
+{
+#if defined (CONFIG_USER_ONLY)
+    env->uncached_cpsr = ARM_CPU_MODE_USR;
+#else
+    /* SVC mode with interrupts disabled.  */
+    env->uncached_cpsr = ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
+#endif
+    env->regs[15] = 0;
+}
+
 CPUARMState *cpu_arm_init(void)
 {
     CPUARMState *env;
 
-    cpu_exec_init();
-
-    env = malloc(sizeof(CPUARMState));
+    env = qemu_mallocz(sizeof(CPUARMState));
     if (!env)
         return NULL;
-    memset(env, 0, sizeof(CPUARMState));
-    cpu_single_env = env;
+    cpu_exec_init(env);
+    cpu_reset(env);
+    tlb_flush(env, 1);
     return env;
 }
 
@@ -2186,6 +2457,10 @@ void cpu_arm_close(CPUARMState *env)
     free(env);
 }
 
+static const char *cpu_mode_names[16] = {
+  "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
+  "???", "???", "???", "und", "???", "???", "???", "sys"
+};
 void cpu_dump_state(CPUState *env, FILE *f, 
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
@@ -2196,6 +2471,7 @@ void cpu_dump_state(CPUState *env, FILE *f,
         float s;
     } s0, s1;
     CPU_DoubleU d;
+    uint32_t psr;
 
     for(i=0;i<16;i++) {
         cpu_fprintf(f, "R%02d=%08x", i, env->regs[i]);
@@ -2204,13 +2480,15 @@ void cpu_dump_state(CPUState *env, FILE *f,
         else
             cpu_fprintf(f, " ");
     }
-    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c\n", 
-             env->cpsr, 
-            env->cpsr & (1 << 31) ? 'N' : '-',
-            env->cpsr & (1 << 30) ? 'Z' : '-',
-            env->cpsr & (1 << 29) ? 'C' : '-',
-            env->cpsr & (1 << 28) ? 'V' : '-',
-            env->thumb ? 'T' : 'A');
+    psr = cpsr_read(env);
+    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d %x\n", 
+                psr, 
+                psr & (1 << 31) ? 'N' : '-',
+                psr & (1 << 30) ? 'Z' : '-',
+                psr & (1 << 29) ? 'C' : '-',
+                psr & (1 << 28) ? 'V' : '-',
+                psr & CPSR_T ? 'T' : 'A', 
+                cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
 
     for (i = 0; i < 16; i++) {
         d.d = env->vfp.regs[i];
@@ -2225,27 +2503,3 @@ void cpu_dump_state(CPUState *env, FILE *f,
     cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.fpscr);
 }
 
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
-{
-    return addr;
-}
-
-#if defined(CONFIG_USER_ONLY) 
-
-int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
-                              int is_user, int is_softmmu)
-{
-    env->cp15_6 = address;
-    if (rw == 2) {
-        env->exception_index = EXCP_PREFETCH_ABORT;
-    } else {
-        env->exception_index = EXCP_DATA_ABORT;
-    }
-    return 1;
-}
-
-#else
-
-#error not implemented
-
-#endif
index f8373a1..450dd8c 100644 (file)
 #define ID_MASK                 0x00200000
 
 /* hidden flags - used internally by qemu to represent additionnal cpu
-   states. Only the CPL and INHIBIT_IRQ are not redundant. We avoid
+   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. */
 /* current cpl */
 #define HF_CS64_SHIFT       15 /* only used on x86_64: 64 bit code segment  */
 #define HF_OSFXSR_SHIFT     16 /* CR4.OSFXSR */
 #define HF_VM_SHIFT         17 /* must be same as eflags */
+#define HF_HALTED_SHIFT     18 /* CPU halted */
 
 #define HF_CPL_MASK          (3 << HF_CPL_SHIFT)
 #define HF_SOFTMMU_MASK      (1 << HF_SOFTMMU_SHIFT)
 #define HF_LMA_MASK          (1 << HF_LMA_SHIFT)
 #define HF_CS64_MASK         (1 << HF_CS64_SHIFT)
 #define HF_OSFXSR_MASK       (1 << HF_OSFXSR_SHIFT)
+#define HF_HALTED_MASK       (1 << HF_HALTED_SHIFT)
 
 #define CR0_PE_MASK  (1 << 0)
 #define CR0_MP_MASK  (1 << 1)
 #define PG_DIRTY_BIT   6
 #define PG_PSE_BIT     7
 #define PG_GLOBAL_BIT  8
+#define PG_NX_BIT      63
 
 #define PG_PRESENT_MASK  (1 << PG_PRESENT_BIT)
 #define PG_RW_MASK      (1 << PG_RW_BIT)
 #define PG_DIRTY_MASK   (1 << PG_DIRTY_BIT)
 #define PG_PSE_MASK     (1 << PG_PSE_BIT)
 #define PG_GLOBAL_MASK  (1 << PG_GLOBAL_BIT)
+#define PG_NX_MASK      (1LL << PG_NX_BIT)
 
 #define PG_ERROR_W_BIT     1
 
 #define PG_ERROR_W_MASK    (1 << PG_ERROR_W_BIT)
 #define PG_ERROR_U_MASK    0x04
 #define PG_ERROR_RSVD_MASK 0x08
+#define PG_ERROR_I_D_MASK  0x10
 
 #define MSR_IA32_APICBASE               0x1b
 #define MSR_IA32_APICBASE_BSP           (1<<8)
@@ -497,28 +502,11 @@ typedef struct CPUX86State {
     int error_code;
     int exception_is_int;
     target_ulong exception_next_eip;
-    struct TranslationBlock *current_tb; /* currently executing TB */
     target_ulong dr[8]; /* debug registers */
     int interrupt_request; 
     int user_mode_only; /* user mode only simulation */
 
-    /* soft mmu support */
-    /* in order to avoid passing too many arguments to the memory
-       write helpers, we store some rarely used information in the CPU
-       context) */
-    unsigned long mem_write_pc; /* host pc at which the memory was
-                                   written */
-    target_ulong mem_write_vaddr; /* target virtual addr at which the
-                                     memory was written */
-    /* 0 = kernel, 1 = user */
-    CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
-    CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
-    
-    /* from this point: preserved by CPU reset */
-    /* ice debug support */
-    target_ulong breakpoints[MAX_BREAKPOINTS];
-    int nb_breakpoints;
-    int singlestep_enabled;
+    CPU_COMMON
 
     /* processor features (e.g. for CPUID insn) */
     uint32_t cpuid_level;
@@ -538,8 +526,6 @@ typedef struct CPUX86State {
     /* in order to simplify APIC support, we leave this pointer to the
        user */
     struct APICState *apic_state;
-    /* user data */
-    void *opaque;
 } CPUX86State;
 
 CPUX86State *cpu_x86_init(void);
index b114501..61ba3cd 100644 (file)
@@ -210,72 +210,9 @@ void check_iob_DX(void);
 void check_iow_DX(void);
 void check_iol_DX(void);
 
-/* XXX: move that to a generic header */
 #if !defined(CONFIG_USER_ONLY)
 
-#define ldul_user ldl_user
-#define ldul_kernel ldl_kernel
-
-#define ACCESS_TYPE 0
-#define MEMSUFFIX _kernel
-#define DATA_SIZE 1
-#include "softmmu_header.h"
-
-#define DATA_SIZE 2
-#include "softmmu_header.h"
-
-#define DATA_SIZE 4
-#include "softmmu_header.h"
-
-#define DATA_SIZE 8
-#include "softmmu_header.h"
-#undef ACCESS_TYPE
-#undef MEMSUFFIX
-
-#define ACCESS_TYPE 1
-#define MEMSUFFIX _user
-#define DATA_SIZE 1
-#include "softmmu_header.h"
-
-#define DATA_SIZE 2
-#include "softmmu_header.h"
-
-#define DATA_SIZE 4
-#include "softmmu_header.h"
-
-#define DATA_SIZE 8
-#include "softmmu_header.h"
-#undef ACCESS_TYPE
-#undef MEMSUFFIX
-
-/* these access are slower, they must be as rare as possible */
-#define ACCESS_TYPE 2
-#define MEMSUFFIX _data
-#define DATA_SIZE 1
-#include "softmmu_header.h"
-
-#define DATA_SIZE 2
-#include "softmmu_header.h"
-
-#define DATA_SIZE 4
-#include "softmmu_header.h"
-
-#define DATA_SIZE 8
-#include "softmmu_header.h"
-#undef ACCESS_TYPE
-#undef MEMSUFFIX
-
-#define ldub(p) ldub_data(p)
-#define ldsb(p) ldsb_data(p)
-#define lduw(p) lduw_data(p)
-#define ldsw(p) ldsw_data(p)
-#define ldl(p) ldl_data(p)
-#define ldq(p) ldq_data(p)
-
-#define stb(p, v) stb_data(p, v)
-#define stw(p, v) stw_data(p, v)
-#define stl(p, v) stl_data(p, v)
-#define stq(p, v) stq_data(p, v)
+#include "softmmu_exec.h"
 
 static inline double ldfq(target_ulong ptr)
 {
index c7fea95..a649242 100644 (file)
@@ -339,7 +339,7 @@ static void switch_tss(int tss_selector,
        necessary to valid the TLB after having done the accesses */
 
     v1 = ldub_kernel(env->tr.base);
-    v2 = ldub(env->tr.base + old_tss_limit_max);
+    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);
     
@@ -1584,7 +1584,7 @@ void load_seg(int seg_reg, int selector)
             
             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);
             }
         }
@@ -1732,11 +1732,11 @@ void helper_lcall_real_T0_T1(int shift, int next_eip)
 /* protected mode call */
 void helper_lcall_protected_T0_T1(int shift, int next_eip_addend)
 {
-    int new_cs, new_eip, new_stack, i;
+    int new_cs, new_stack, i;
     uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
     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;
+    target_ulong ssp, old_ssp, next_eip, new_eip;
     
     new_cs = T0;
     new_eip = T1;
@@ -1744,7 +1744,7 @@ void helper_lcall_protected_T0_T1(int shift, int next_eip_addend)
 #ifdef DEBUG_PCALL
     if (loglevel & CPU_LOG_PCALL) {
         fprintf(logfile, "lcall %04x:%08x s=%d\n",
-                new_cs, new_eip, shift);
+                new_cs, (uint32_t)new_eip, shift);
         cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
     }
 #endif
@@ -1986,7 +1986,14 @@ static inline void validate_seg(int seg_reg, int cpl)
 {
     int dpl;
     uint32_t e2;
-    
+
+    /* 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) && 
+        (env->segs[seg_reg].selector & 0xfffc) == 0)
+        return;
+
     e2 = env->segs[seg_reg].flags;
     dpl = (e2 >> DESC_DPL_SHIFT) & 3;
     if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
@@ -2152,10 +2159,10 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
             sp_mask = get_sp_mask(ss_e2);
 
         /* validate data segments */
-        validate_seg(R_ES, cpl);
-        validate_seg(R_DS, cpl);
-        validate_seg(R_FS, cpl);
-        validate_seg(R_GS, cpl);
+        validate_seg(R_ES, rpl);
+        validate_seg(R_DS, rpl);
+        validate_seg(R_FS, rpl);
+        validate_seg(R_GS, rpl);
 
         sp += addend;
     }
@@ -3261,7 +3268,7 @@ static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
 static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
 {
     uint64_t q, r, a1, a0;
-    int i, qb;
+    int i, qb, ab;
 
     a0 = *plow;
     a1 = *phigh;
@@ -3275,8 +3282,9 @@ static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
             return 1;
         /* XXX: use a better algorithm */
         for(i = 0; i < 64; i++) {
+            ab = a1 >> 63;
             a1 = (a1 << 1) | (a0 >> 63);
-            if (a1 >= b) {
+            if (ab || a1 >= b) {
                 a1 -= b;
                 qb = 1;
             } else {
@@ -3477,9 +3485,9 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
             }
         }
         if (retaddr)
-            raise_exception_err(EXCP0E_PAGE, env->error_code);
+            raise_exception_err(env->exception_index, env->error_code);
         else
-            raise_exception_err_norestore(EXCP0E_PAGE, env->error_code);
+            raise_exception_err_norestore(env->exception_index, env->error_code);
     }
     env = saved_env;
 }
index 6033590..cb896cb 100644 (file)
@@ -47,12 +47,11 @@ CPUX86State *cpu_x86_init(void)
     CPUX86State *env;
     static int inited;
 
-    cpu_exec_init();
-
-    env = malloc(sizeof(CPUX86State));
+    env = qemu_mallocz(sizeof(CPUX86State));
     if (!env)
         return NULL;
-    memset(env, 0, sizeof(CPUX86State));
+    cpu_exec_init(env);
+
     /* init various static tables */
     if (!inited) {
         inited = 1;
@@ -128,14 +127,13 @@ CPUX86State *cpu_x86_init(void)
         /* currently not enabled for std i386 because not fully tested */
         env->cpuid_features |= CPUID_APIC;
         env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
-        env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL;
+        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;
 #endif
     }
-    cpu_single_env = env;
     cpu_reset(env);
 #ifdef USE_KQEMU
     kqemu_init(env);
@@ -267,7 +265,7 @@ void cpu_dump_state(CPUState *env, FILE *f,
                     "RSI=%016llx RDI=%016llx RBP=%016llx RSP=%016llx\n"
                     "R8 =%016llx R9 =%016llx R10=%016llx R11=%016llx\n"
                     "R12=%016llx R13=%016llx R14=%016llx R15=%016llx\n"
-                    "RIP=%016llx RFL=%08x [%c%c%c%c%c%c%c]    CPL=%d II=%d A20=%d\n",
+                    "RIP=%016llx RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n",
                     env->regs[R_EAX], 
                     env->regs[R_EBX], 
                     env->regs[R_ECX], 
@@ -294,13 +292,14 @@ void cpu_dump_state(CPUState *env, FILE *f,
                     eflags & CC_C ? 'C' : '-',
                     env->hflags & HF_CPL_MASK, 
                     (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
-                    (env->a20_mask >> 20) & 1);
+                    (env->a20_mask >> 20) & 1,
+                    (env->hflags >> HF_HALTED_SHIFT) & 1);
     } 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\n",
+                    "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n",
                     (uint32_t)env->regs[R_EAX], 
                     (uint32_t)env->regs[R_EBX], 
                     (uint32_t)env->regs[R_ECX], 
@@ -319,7 +318,8 @@ void cpu_dump_state(CPUState *env, FILE *f,
                     eflags & CC_C ? 'C' : '-',
                     env->hflags & HF_CPL_MASK, 
                     (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
-                    (env->a20_mask >> 20) & 1);
+                    (env->a20_mask >> 20) & 1,
+                    (env->hflags >> HF_HALTED_SHIFT) & 1);
     }
 
 #ifdef TARGET_X86_64
@@ -566,6 +566,7 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
     env->cr[2] = addr;
     env->error_code = (is_write << PG_ERROR_W_BIT);
     env->error_code |= PG_ERROR_U_MASK;
+    env->exception_index = EXCP0E_PAGE;
     return 1;
 }
 
@@ -576,6 +577,8 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 
 #else
 
+#define PHYS_ADDR_MASK 0xfffff000
+
 /* return value:
    -1 = cannot handle fault 
    0  = nothing more to do 
@@ -583,101 +586,176 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
    2  = soft MMU activation required for this block
 */
 int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, 
-                             int is_write, int is_user, int is_softmmu)
+                             int is_write1, int is_user, int is_softmmu)
 {
+    uint64_t ptep, pte;
     uint32_t pdpe_addr, pde_addr, pte_addr;
-    uint32_t pde, pte, ptep, pdpe;
-    int error_code, is_dirty, prot, page_size, ret;
+    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", 
-           addr, is_write, is_user, env->eip);
+           addr, is_write1, is_user, env->eip);
 #endif
-    is_write &= 1;
+    is_write = is_write1 & 1;
     
     if (!(env->cr[0] & CR0_PG_MASK)) {
         pte = addr;
         virt_addr = addr & TARGET_PAGE_MASK;
-        prot = PAGE_READ | PAGE_WRITE;
+        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
         page_size = 4096;
         goto do_mapping;
     }
 
     if (env->cr[4] & CR4_PAE_MASK) {
+        uint64_t pde, pdpe;
+
         /* XXX: we only use 32 bit physical addresses */
 #ifdef TARGET_X86_64
         if (env->hflags & HF_LMA_MASK) {
-            uint32_t pml4e_addr, pml4e;
+            uint32_t pml4e_addr;
+            uint64_t pml4e;
             int32_t sext;
 
-            /* XXX: handle user + rw rights */
-            /* XXX: handle NX flag */
             /* test virtual address sign extension */
             sext = (int64_t)addr >> 47;
             if (sext != 0 && sext != -1) {
-                error_code = 0;
-                goto do_fault;
+                env->error_code = 0;
+                env->exception_index = EXCP0D_GPF;
+                return 1;
             }
             
             pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & 
                 env->a20_mask;
-            pml4e = ldl_phys(pml4e_addr);
+            pml4e = ldq_phys(pml4e_addr);
             if (!(pml4e & PG_PRESENT_MASK)) {
                 error_code = 0;
                 goto do_fault;
             }
+            if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) {
+                error_code = PG_ERROR_RSVD_MASK;
+                goto do_fault;
+            }
             if (!(pml4e & PG_ACCESSED_MASK)) {
                 pml4e |= PG_ACCESSED_MASK;
                 stl_phys_notdirty(pml4e_addr, pml4e);
             }
-            
-            pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & 
+            ptep = pml4e ^ PG_NX_MASK;
+            pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) & 
                 env->a20_mask;
-            pdpe = ldl_phys(pdpe_addr);
+            pdpe = ldq_phys(pdpe_addr);
             if (!(pdpe & PG_PRESENT_MASK)) {
                 error_code = 0;
                 goto do_fault;
             }
+            if (!(env->efer & MSR_EFER_NXE) && (pdpe & PG_NX_MASK)) {
+                error_code = PG_ERROR_RSVD_MASK;
+                goto do_fault;
+            }
+            ptep &= pdpe ^ PG_NX_MASK;
             if (!(pdpe & PG_ACCESSED_MASK)) {
                 pdpe |= PG_ACCESSED_MASK;
                 stl_phys_notdirty(pdpe_addr, pdpe);
             }
-        } else 
+        } else
 #endif
         {
+            /* XXX: load them when cr3 is loaded ? */
             pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) & 
                 env->a20_mask;
-            pdpe = ldl_phys(pdpe_addr);
+            pdpe = ldq_phys(pdpe_addr);
             if (!(pdpe & PG_PRESENT_MASK)) {
                 error_code = 0;
                 goto do_fault;
             }
+            ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
         }
 
-        pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) &
+        pde_addr = ((pdpe & PHYS_ADDR_MASK) + (((addr >> 21) & 0x1ff) << 3)) &
             env->a20_mask;
-        pde = ldl_phys(pde_addr);
+        pde = ldq_phys(pde_addr);
         if (!(pde & PG_PRESENT_MASK)) {
             error_code = 0;
             goto do_fault;
         }
+        if (!(env->efer & MSR_EFER_NXE) && (pde & PG_NX_MASK)) {
+            error_code = PG_ERROR_RSVD_MASK;
+            goto do_fault;
+        }
+        ptep &= pde ^ PG_NX_MASK;
         if (pde & PG_PSE_MASK) {
             /* 2 MB page */
             page_size = 2048 * 1024;
-            goto handle_big_page;
+            ptep ^= PG_NX_MASK;
+            if ((ptep & PG_NX_MASK) && is_write1 == 2)
+                goto do_fault_protect;
+            if (is_user) {
+                if (!(ptep & PG_USER_MASK))
+                    goto do_fault_protect;
+                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)) 
+                    goto do_fault_protect;
+            }
+            is_dirty = is_write && !(pde & PG_DIRTY_MASK);
+            if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
+                pde |= PG_ACCESSED_MASK;
+                if (is_dirty)
+                    pde |= PG_DIRTY_MASK;
+                stl_phys_notdirty(pde_addr, pde);
+            }
+            /* align to page_size */
+            pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff); 
+            virt_addr = addr & ~(page_size - 1);
         } else {
             /* 4 KB page */
             if (!(pde & PG_ACCESSED_MASK)) {
                 pde |= PG_ACCESSED_MASK;
                 stl_phys_notdirty(pde_addr, pde);
             }
-            pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) &
+            pte_addr = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff) << 3)) &
                 env->a20_mask;
-            goto handle_4k_page;
+            pte = ldq_phys(pte_addr);
+            if (!(pte & PG_PRESENT_MASK)) {
+                error_code = 0;
+                goto do_fault;
+            }
+            if (!(env->efer & MSR_EFER_NXE) && (pte & PG_NX_MASK)) {
+                error_code = PG_ERROR_RSVD_MASK;
+                goto do_fault;
+            }
+            /* combine pde and pte nx, user and rw protections */
+            ptep &= pte ^ PG_NX_MASK;
+            ptep ^= PG_NX_MASK;
+            if ((ptep & PG_NX_MASK) && is_write1 == 2)
+                goto do_fault_protect; 
+            if (is_user) {
+                if (!(ptep & PG_USER_MASK))
+                    goto do_fault_protect;
+                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)) 
+                    goto do_fault_protect;
+            }
+            is_dirty = is_write && !(pte & PG_DIRTY_MASK);
+            if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
+                pte |= PG_ACCESSED_MASK;
+                if (is_dirty)
+                    pte |= PG_DIRTY_MASK;
+                stl_phys_notdirty(pte_addr, pte);
+            }
+            page_size = 4096;
+            virt_addr = addr & ~0xfff;
+            pte = pte & (PHYS_ADDR_MASK | 0xfff);
         }
     } else {
+        uint32_t pde;
+
         /* page directory entry */
         pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & 
             env->a20_mask;
@@ -689,7 +767,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
         /* if PSE bit is set, then we use a 4MB page */
         if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
             page_size = 4096 * 1024;
-        handle_big_page:
             if (is_user) {
                 if (!(pde & PG_USER_MASK))
                     goto do_fault_protect;
@@ -720,7 +797,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
             /* page directory entry */
             pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & 
                 env->a20_mask;
-        handle_4k_page:
             pte = ldl_phys(pte_addr);
             if (!(pte & PG_PRESENT_MASK)) {
                 error_code = 0;
@@ -748,20 +824,21 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
             page_size = 4096;
             virt_addr = addr & ~0xfff;
         }
-
-        /* the page can be put in the TLB */
-        prot = PAGE_READ;
-        if (pte & PG_DIRTY_MASK) {
-            /* only set write access if already dirty... otherwise wait
-               for dirty access */
-            if (is_user) {
-                if (ptep & PG_RW_MASK)
-                    prot |= PAGE_WRITE;
-            } else {
-                if (!(env->cr[0] & CR0_WP_MASK) ||
-                    (ptep & PG_RW_MASK))
-                    prot |= PAGE_WRITE;
-            }
+    }
+    /* the page can be put in the TLB */
+    prot = PAGE_READ;
+    if (!(ptep & PG_NX_MASK))
+        prot |= PAGE_EXEC;
+    if (pte & PG_DIRTY_MASK) {
+        /* only set write access if already dirty... otherwise wait
+           for dirty access */
+        if (is_user) {
+            if (ptep & PG_RW_MASK)
+                prot |= PAGE_WRITE;
+        } else {
+            if (!(env->cr[0] & CR0_WP_MASK) ||
+                (ptep & PG_RW_MASK))
+                prot |= PAGE_WRITE;
         }
     }
  do_mapping:
@@ -773,15 +850,21 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
     paddr = (pte & TARGET_PAGE_MASK) + page_offset;
     vaddr = virt_addr + page_offset;
     
-    ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
+    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;
-    env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;
+    error_code |= (is_write << PG_ERROR_W_BIT);
     if (is_user)
-        env->error_code |= PG_ERROR_U_MASK;
+        error_code |= PG_ERROR_U_MASK;
+    if (is_write1 == 2 && 
+        (env->efer & MSR_EFER_NXE) && 
+        (env->cr[4] & CR4_PAE_MASK))
+        error_code |= PG_ERROR_I_D_MASK;
+    env->error_code = error_code;
+    env->exception_index = EXCP0E_PAGE;
     return 1;
 }
 
index 6370045..137f572 100644 (file)
@@ -615,6 +615,7 @@ void OPPROTO op_movq_eip_im64(void)
 void OPPROTO op_hlt(void)
 {
     env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
+    env->hflags |= HF_HALTED_MASK;
     env->exception_index = EXCP_HLT;
     cpu_loop_exit();
 }
index 0002f0d..7ec84dd 100644 (file)
@@ -45,7 +45,7 @@ void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T1_A0)(void)
 
 void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T1_A0)(void)
 {
-    T1 = glue(ldl, MEMSUFFIX)(A0);
+    T1 = (uint32_t)glue(ldl, MEMSUFFIX)(A0);
 }
 
 void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void)
index 0f6b0eb..dab0378 100644 (file)
@@ -1700,6 +1700,31 @@ static inline int insn_const_size(unsigned int ot)
         return 4;
 }
 
+static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
+{
+    TranslationBlock *tb;
+    target_ulong pc;
+
+    pc = s->cs_base + eip;
+    tb = s->tb;
+    /* NOTE: we handle the case where the TB spans two pages here */
+    if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) ||
+        (pc & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK))  {
+        /* jump to same page: we can use a direct jump */
+        if (tb_num == 0)
+            gen_op_goto_tb0(TBPARAM(tb));
+        else
+            gen_op_goto_tb1(TBPARAM(tb));
+        gen_jmp_im(eip);
+        gen_op_movl_T0_im((long)tb + tb_num);
+        gen_op_exit_tb();
+    } else {
+        /* jump to another page: currently not optimized */
+        gen_jmp_im(eip);
+        gen_eob(s);
+    }
+}
+
 static inline void gen_jcc(DisasContext *s, int b, 
                            target_ulong val, target_ulong next_eip)
 {
@@ -1779,8 +1804,10 @@ static inline void gen_jcc(DisasContext *s, int b,
             break;
         }
 
-        if (s->cc_op != CC_OP_DYNAMIC)
+        if (s->cc_op != CC_OP_DYNAMIC) {
             gen_op_set_cc_op(s->cc_op);
+            s->cc_op = CC_OP_DYNAMIC;
+        }
 
         if (!func) {
             gen_setcc_slow[jcc_op]();
@@ -1797,16 +1824,10 @@ static inline void gen_jcc(DisasContext *s, int b,
         l1 = gen_new_label();
         func(l1);
 
-        gen_op_goto_tb0(TBPARAM(tb));
-        gen_jmp_im(next_eip);
-        gen_op_movl_T0_im((long)tb + 0);
-        gen_op_exit_tb();
+        gen_goto_tb(s, 0, next_eip);
 
         gen_set_label(l1);
-        gen_op_goto_tb1(TBPARAM(tb));
-        gen_jmp_im(val);
-        gen_op_movl_T0_im((long)tb + 1);
-        gen_op_exit_tb();
+        gen_goto_tb(s, 1, val);
 
         s->is_jmp = 3;
     } else {
@@ -2217,18 +2238,12 @@ static void gen_eob(DisasContext *s)
    direct call to the next block may occur */
 static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num)
 {
-    TranslationBlock *tb = s->tb;
-
     if (s->jmp_opt) {
-        if (s->cc_op != CC_OP_DYNAMIC)
+        if (s->cc_op != CC_OP_DYNAMIC) {
             gen_op_set_cc_op(s->cc_op);
-        if (tb_num)
-            gen_op_goto_tb1(TBPARAM(tb));
-        else
-            gen_op_goto_tb0(TBPARAM(tb));
-        gen_jmp_im(eip);
-        gen_op_movl_T0_im((long)tb + tb_num);
-        gen_op_exit_tb();
+            s->cc_op = CC_OP_DYNAMIC;
+        }
+        gen_goto_tb(s, tb_num, eip);
         s->is_jmp = 3;
     } else {
         gen_jmp_im(eip);
index 8ed09d5..5e4b91d 100644 (file)
@@ -1,6 +1,8 @@
 #if !defined (__MIPS_CPU_H__)
 #define __MIPS_CPU_H__
 
+#define TARGET_HAS_ICE 1
+
 #include "mips-defs.h"
 #include "cpu-defs.h"
 #include "config.h"
@@ -18,6 +20,7 @@ typedef struct tlb_t tlb_t;
 struct tlb_t {
     target_ulong VPN;
     target_ulong end;
+    target_ulong end2;
     uint8_t ASID;
     uint8_t G;
     uint8_t C[2];
@@ -151,35 +154,21 @@ struct CPUMIPSState {
 #define MIPS_HFLAG_DM     0x0008 /* Debug mode                         */
 #define MIPS_HFLAG_SM     0x0010 /* Supervisor mode                    */
 #define MIPS_HFLAG_RE     0x0040 /* Reversed endianness                */
-#define MIPS_HFLAG_DS     0x0080 /* In / out of delay slot             */
-    /* Those flags keep the branch state if the translation is interrupted
-     * between the branch instruction and the delay slot
-     */
-#define MIPS_HFLAG_BMASK  0x0F00
-#define MIPS_HFLAG_B      0x0100 /* Unconditional branch               */
-#define MIPS_HFLAG_BC     0x0200 /* Conditional branch                 */
-#define MIPS_HFLAG_BL     0x0400 /* Likely branch                      */
-#define MIPS_HFLAG_BR     0x0800 /* branch to register (can't link TB) */
+    /* 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) */
     target_ulong btarget;        /* Jump / branch target               */
     int bcond;                   /* Branch condition (if needed)       */
-    struct TranslationBlock *current_tb; /* currently executing TB  */
-    /* soft mmu support */
-    /* in order to avoid passing too many arguments to the memory
-       write helpers, we store some rarely used information in the CPU
-       context) */
-    target_ulong mem_write_pc; /* host pc at which the memory was
-                                   written */
-    unsigned long mem_write_vaddr; /* target virtual addr at which the
-                                      memory was written */
-    /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */
-    CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
-    CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
-    /* ice debug support */
-    target_ulong breakpoints[MAX_BREAKPOINTS];
-    int nb_breakpoints;
-    int singlestep_enabled; /* XXX: should use CPU single step mode instead */
-    /* user data */
-    void *opaque;
+
+    int halted; /* TRUE if the CPU is in suspend state */
+
+    CPU_COMMON
 };
 
 #include "cpu-all.h"
@@ -218,15 +207,15 @@ enum {
     EXCP_IBE,
     EXCP_DBp,
     EXCP_SYSCALL,
-    EXCP_BREAK,
-    EXCP_CpU, /* 16 */
+    EXCP_BREAK, /* 16 */
+    EXCP_CpU,
     EXCP_RI,
     EXCP_OVERFLOW,
     EXCP_TRAP,
     EXCP_DDBS,
     EXCP_DWATCH,
-    EXCP_LAE, /* 22 */
-    EXCP_SAE,
+    EXCP_LAE,
+    EXCP_SAE, /* 24 */
     EXCP_LTLBL,
     EXCP_TLBL,
     EXCP_TLBS,
index 77fce26..ed9094c 100644 (file)
@@ -1,7 +1,7 @@
 #if !defined(__QEMU_MIPS_EXEC_H__)
 #define __QEMU_MIPS_EXEC_H__
 
-#define DEBUG_OP
+//#define DEBUG_OP
 
 #include "mips-defs.h"
 #include "dyngen-exec.h"
@@ -40,71 +40,7 @@ register double FT2 asm(FREG2);
 #include "exec-all.h"
 
 #if !defined(CONFIG_USER_ONLY)
-
-#define ldul_user ldl_user
-#define ldul_kernel ldl_kernel
-
-#define ACCESS_TYPE 0
-#define MEMSUFFIX _kernel
-#define DATA_SIZE 1
-#include "softmmu_header.h"
-
-#define DATA_SIZE 2
-#include "softmmu_header.h"
-
-#define DATA_SIZE 4
-#include "softmmu_header.h"
-
-#define DATA_SIZE 8
-#include "softmmu_header.h"
-#undef ACCESS_TYPE
-#undef MEMSUFFIX
-
-#define ACCESS_TYPE 1
-#define MEMSUFFIX _user
-#define DATA_SIZE 1
-#include "softmmu_header.h"
-
-#define DATA_SIZE 2
-#include "softmmu_header.h"
-
-#define DATA_SIZE 4
-#include "softmmu_header.h"
-
-#define DATA_SIZE 8
-#include "softmmu_header.h"
-#undef ACCESS_TYPE
-#undef MEMSUFFIX
-
-/* these access are slower, they must be as rare as possible */
-#define ACCESS_TYPE 2
-#define MEMSUFFIX _data
-#define DATA_SIZE 1
-#include "softmmu_header.h"
-
-#define DATA_SIZE 2
-#include "softmmu_header.h"
-
-#define DATA_SIZE 4
-#include "softmmu_header.h"
-
-#define DATA_SIZE 8
-#include "softmmu_header.h"
-#undef ACCESS_TYPE
-#undef MEMSUFFIX
-
-#define ldub(p) ldub_data(p)
-#define ldsb(p) ldsb_data(p)
-#define lduw(p) lduw_data(p)
-#define ldsw(p) ldsw_data(p)
-#define ldl(p) ldl_data(p)
-#define ldq(p) ldq_data(p)
-
-#define stb(p, v) stb_data(p, v)
-#define stw(p, v) stw_data(p, v)
-#define stl(p, v) stl_data(p, v)
-#define stq(p, v) stq_data(p, v)
-
+#include "softmmu_exec.h"
 #endif /* !defined(CONFIG_USER_ONLY) */
 
 static inline void env_to_regs(void)
@@ -129,19 +65,19 @@ void do_tlbwi (void);
 void do_tlbwr (void);
 void do_tlbp (void);
 void do_tlbr (void);
-void do_lwl_raw (void);
-void do_lwr_raw (void);
-void do_swl_raw (void);
-void do_swr_raw (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);
 #if !defined(CONFIG_USER_ONLY)
-void do_lwl_user (void);
-void do_lwl_kernel (void);
-void do_lwr_user (void);
-void do_lwr_kernel (void);
-void do_swl_user (void);
-void do_swl_kernel (void);
-void do_swr_user (void);
-void do_swr_kernel (void);
+void do_lwl_user (uint32_t);
+void do_lwl_kernel (uint32_t);
+void do_lwr_user (uint32_t);
+void do_lwr_kernel (uint32_t);
+uint32_t do_swl_user (uint32_t);
+uint32_t do_swl_kernel (uint32_t);
+uint32_t do_swr_user (uint32_t);
+uint32_t do_swr_kernel (uint32_t);
 #endif
 void do_pmon (int function);
 
@@ -152,6 +88,7 @@ void do_interrupt (CPUState *env);
 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 (uint32_t exception);
 
 void cpu_dump_state(CPUState *env, FILE *f, 
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
index 8d26175..8b4deb3 100644 (file)
@@ -46,7 +46,7 @@ static int map_address (CPUState *env, target_ulong *physical, int *prot,
         tlb = &env->tlb[i];
         /* Check ASID, virtual page number & size */
         if ((tlb->G == 1 || tlb->ASID == ASID) &&
-            tlb->VPN == tag && address < tlb->end) {
+            tlb->VPN == tag && address < tlb->end2) {
             /* TLB match */
             n = (address >> 12) & 1;
             /* Check access rights */
@@ -167,10 +167,15 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
     int ret = 0;
 
     if (logfile) {
+#if 0
         cpu_dump_state(env, logfile, fprintf, 0);
+#endif
         fprintf(logfile, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n",
                 __func__, env->PC, address, rw, is_user, is_softmmu);
     }
+
+    rw &= 1;
+
     /* data access */
     /* XXX: put correct access by using cpu_restore_state()
        correctly */
@@ -226,7 +231,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
         /* Raise exception */
         env->CP0_BadVAddr = address;
         env->CP0_Context = (env->CP0_Context & 0xff800000) |
-                          ((address >> 8) &   0x007ffff0);
+                          ((address >> 9) &   0x007ffff0);
         env->CP0_EntryHi =
             (env->CP0_EntryHi & 0x000000FF) | (address & 0xFFFFF000);
         env->exception_index = exception;
@@ -276,11 +281,12 @@ void do_interrupt (CPUState *env)
         env->CP0_Debug |= 1 << CP0DB_DDBL;
         goto set_DEPC;
     set_DEPC:
-        if (env->hflags & MIPS_HFLAG_DS) {
+        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->hflags &= ~MIPS_HFLAG_BMASK;
         } else {
             env->CP0_DEPC = env->PC;
         }
@@ -316,8 +322,7 @@ void do_interrupt (CPUState *env)
         env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) |
             (1 << CP0St_NMI);
     set_error_EPC:
-        env->hflags = MIPS_HFLAG_ERL;
-        if (env->hflags & MIPS_HFLAG_DS) {
+        if (env->hflags & MIPS_HFLAG_BMASK) {
             /* If the exception was raised from a delay slot,
              * come back to the jump
              */
@@ -325,6 +330,7 @@ void do_interrupt (CPUState *env)
         } else {
             env->CP0_ErrorEPC = env->PC;
         }
+        env->hflags = MIPS_HFLAG_ERL;
         pc = 0xBFC00000;
         break;
     case EXCP_MCHECK:
@@ -366,7 +372,7 @@ void do_interrupt (CPUState *env)
         goto set_EPC;
     case EXCP_CpU:
         cause = 11;
-        /* XXX: fill in the faulty unit number */
+        env->CP0_Cause = (env->CP0_Cause & ~0x03000000) | (env->error_code << 28);
         goto set_EPC;
     case EXCP_OVERFLOW:
         cause = 12;
@@ -391,12 +397,13 @@ void do_interrupt (CPUState *env)
         env->hflags |= MIPS_HFLAG_EXL;
         pc += offset;
         env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2);
-        if (env->hflags & MIPS_HFLAG_DS) {
+        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;
index 32f7e4f..71abd95 100644 (file)
@@ -207,7 +207,7 @@ void op_addo (void)
     tmp = T0;
     T0 += T1;
     if ((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31)) {
-        CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
+        CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
     }
     RETURN();
 }
@@ -225,7 +225,7 @@ void op_subo (void)
     tmp = T0;
     T0 = (int32_t)T0 - (int32_t)T1;
     if (!((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31))) {
-        CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
+        CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
     }
     RETURN();
 }
@@ -364,7 +364,7 @@ static inline void set_HILO (uint64_t HILO)
 
 void op_mult (void)
 {
-    set_HILO((int64_t)T0 * (int64_t)T1);
+    set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
     RETURN();
 }
 
@@ -378,7 +378,7 @@ void op_madd (void)
 {
     int64_t tmp;
 
-    tmp = ((int64_t)T0 * (int64_t)T1);
+    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
     set_HILO((int64_t)get_HILO() + tmp);
     RETURN();
 }
@@ -396,7 +396,7 @@ void op_msub (void)
 {
     int64_t tmp;
 
-    tmp = ((int64_t)T0 * (int64_t)T1);
+    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
     set_HILO((int64_t)get_HILO() - tmp);
     RETURN();
 }
@@ -487,7 +487,16 @@ OP_COND(ltz, (int32_t)T0 < 0);
 
 /* Branchs */
 //#undef USE_DIRECT_JUMP
-#define EIP env->PC
+
+void OPPROTO op_goto_tb0(void)
+{
+    GOTO_TB(op_goto_tb0, PARAM1, 0);
+}
+
+void OPPROTO op_goto_tb1(void)
+{
+    GOTO_TB(op_goto_tb1, PARAM1, 1);
+}
 
 /* Branch to register */
 void op_save_breg_target (void)
@@ -506,13 +515,6 @@ void op_breg (void)
     RETURN();
 }
 
-/* Unconditional branch */
-void op_branch (void)
-{
-    JUMP_TB(branch, PARAM1, 0, PARAM2);
-    RETURN();
-}
-
 void op_save_btarget (void)
 {
     env->btarget = PARAM1;
@@ -538,24 +540,10 @@ void op_restore_bcond (void)
     RETURN();
 }
 
-void op_bcond (void)
-{
-    if (T2) {
-        JUMP_TB(bcond, PARAM1, 0, PARAM2);
-    } else {
-        JUMP_TB(bcond, PARAM1, 1, PARAM3);
-    }
-    RETURN();
-}
-
-/* Likely branch (used to skip the delay slot) */
-void op_blikely (void)
+void op_jnz_T2 (void)
 {
-    /* If the test is false, skip the delay slot */
-    if (T2 == 0) {
-        env->hflags = PARAM3;
-        JUMP_TB(blikely, PARAM1, 1, PARAM2);
-    }
+    if (T2)
+        GOTO_LABEL_PARAM(1);
     RETURN();
 }
 
@@ -607,11 +595,16 @@ void op_pmon (void)
 void op_trap (void)
 {
     if (T0) {
-        CALL_FROM_TB1(do_raise_exception, EXCP_TRAP);
+        CALL_FROM_TB1(do_raise_exception_direct, EXCP_TRAP);
     }
     RETURN();
 }
 
+void op_debug (void)
+{
+  CALL_FROM_TB1(do_raise_exception_direct, EXCP_DEBUG);
+}
+
 void op_set_lladdr (void)
 {
     env->CP0_LLAddr = T2;
@@ -666,3 +659,8 @@ void op_exit_tb (void)
     EXIT_TB();
 }
 
+void op_wait (void)
+{
+    env->halted = 1;
+    CALL_FROM_TB1(do_raise_exception, EXCP_HLT);
+}
index b8397be..be207b9 100644 (file)
@@ -22,6 +22,8 @@
 
 #define MIPS_DEBUG_DISAS
 
+#define GETPC() (__builtin_return_address(0))
+
 /*****************************************************************************/
 /* Exceptions processing helpers */
 void cpu_loop_exit(void)
@@ -46,6 +48,21 @@ void do_raise_exception (uint32_t exception)
     do_raise_exception_err(exception, 0);
 }
 
+void do_restore_state (void *pc_ptr)
+{
+  TranslationBlock *tb;
+  unsigned long pc = (unsigned long) pc_ptr;
+
+  tb = tb_find_pc (pc);
+  cpu_restore_state (tb, env, pc, NULL);
+}
+
+void do_raise_exception_direct (uint32_t exception)
+{
+    do_restore_state (GETPC ());
+    do_raise_exception_err (exception, 0);
+}
+
 #define MEMSUFFIX _raw
 #include "op_helper_mem.c"
 #undef MEMSUFFIX
@@ -73,7 +90,7 @@ static inline void set_HILO (uint64_t HILO)
 
 void do_mult (void)
 {
-    set_HILO((int64_t)T0 * (int64_t)T1);
+    set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
 }
 
 void do_multu (void)
@@ -85,7 +102,7 @@ void do_madd (void)
 {
     int64_t tmp;
 
-    tmp = ((int64_t)T0 * (int64_t)T1);
+    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
     set_HILO((int64_t)get_HILO() + tmp);
 }
 
@@ -101,7 +118,7 @@ void do_msub (void)
 {
     int64_t tmp;
 
-    tmp = ((int64_t)T0 * (int64_t)T1);
+    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
     set_HILO((int64_t)get_HILO() - tmp);
 }
 
@@ -114,6 +131,37 @@ void do_msubu (void)
 }
 #endif
 
+#if defined(CONFIG_USER_ONLY) 
+void do_mfc0 (int reg, int sel)
+{
+    cpu_abort(env, "mfc0 reg=%d sel=%d\n", reg, sel);
+}
+void do_mtc0 (int reg, int sel)
+{
+    cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel);
+}
+
+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");
+}
+#else
+
 /* CP0 helpers */
 void do_mfc0 (int reg, int sel)
 {
@@ -322,6 +370,9 @@ void do_mtc0 (int reg, int sel)
         val = T0 & 0xFFFFF0FF;
         old = env->CP0_EntryHi;
         env->CP0_EntryHi = val;
+       /* If the ASID changes, flush qemu's TLB.  */
+       if ((old & 0xFF) != (val & 0xFF))
+         tlb_flush (env, 1);
         rn = "EntryHi";
         break;
     case 11:
@@ -494,11 +545,25 @@ static void invalidate_tb (int idx)
         addr = tlb->PFN[0];
         end = addr + (tlb->end - tlb->VPN);
         tb_invalidate_page_range(addr, end);
+        /* FIXME: Might be faster to just invalidate the whole "tlb" here
+           and refill it on demand from our simulated TLB.  */
+        addr = tlb->VPN;
+        while (addr < tlb->end) {
+            tlb_flush_page (env, addr);
+            addr += TARGET_PAGE_SIZE;
+        }
     }
     if (tlb->V[1]) {
         addr = tlb->PFN[1];
         end = addr + (tlb->end - tlb->VPN);
         tb_invalidate_page_range(addr, end);
+        /* FIXME: Might be faster to just invalidate the whole "tlb" here
+           and refill it on demand from our simulated TLB.  */
+        addr = tlb->end;
+        while (addr < tlb->end2) {
+            tlb_flush_page (env, addr);
+            addr += TARGET_PAGE_SIZE;
+        }
     }
 }
 
@@ -514,6 +579,7 @@ static void fill_tb (int idx)
     size = env->CP0_PageMask >> 13;
     size = 4 * (size + 1);
     tlb->end = tlb->VPN + (1 << (8 + size));
+    tlb->end2 = tlb->end + (1 << (8 + size));
     tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
     tlb->V[0] = env->CP0_EntryLo0 & 2;
     tlb->D[0] = env->CP0_EntryLo0 & 4;
@@ -570,6 +636,12 @@ void do_tlbr (void)
     int size;
 
     tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)];
+
+    /* If this will change the current ASID, flush qemu's TLB.  */
+    /* FIXME: Could avoid flushing things which match global entries... */
+    if ((env->CP0_EntryHi & 0xFF) != tlb->ASID)
+      tlb_flush (env, 1);
+
     env->CP0_EntryHi = tlb->VPN | tlb->ASID;
     size = (tlb->end - tlb->VPN) >> 12;
     env->CP0_PageMask = (size - 1) << 13;
@@ -580,6 +652,8 @@ void do_tlbr (void)
 }
 #endif
 
+#endif /* !CONFIG_USER_ONLY */
+
 void op_dump_ldst (const unsigned char *func)
 {
     if (loglevel)
@@ -631,8 +705,10 @@ void do_pmon (int function)
 
 #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 GETPC() (__builtin_return_address(0))
+#define ALIGNED_ONLY
 
 #define SHIFT 0
 #include "softmmu_template.h"
@@ -646,6 +722,13 @@ void do_pmon (int function)
 #define SHIFT 3
 #include "softmmu_template.h"
 
+static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
+{
+    env->CP0_BadVAddr = addr;
+    do_restore_state (retaddr);
+    do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
+}
+
 void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
 {
     TranslationBlock *tb;
index 69793b0..4711f7a 100644 (file)
@@ -1,15 +1,19 @@
-void glue(do_lwl, MEMSUFFIX) (void)
+#ifdef TARGET_WORDS_BIGENDIAN
+#define GET_LMASK(v) ((v) & 3)
+#else
+#define GET_LMASK(v) (((v) & 3) ^ 3)
+#endif
+
+void glue(do_lwl, MEMSUFFIX) (uint32_t tmp)
 {
 #if defined (DEBUG_OP)
     target_ulong sav = T0;
 #endif
-    uint32_t tmp;
 
-    tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
     /* XXX: this is valid only in big-endian mode
      *      should be reverted for little-endian...
      */
-    switch (T0 & 3) {
+    switch (GET_LMASK(T0)) {
     case 0:
         T0 = tmp;
         break;
@@ -32,18 +36,16 @@ void glue(do_lwl, MEMSUFFIX) (void)
     RETURN();
 }
 
-void glue(do_lwr, MEMSUFFIX) (void)
+void glue(do_lwr, MEMSUFFIX) (uint32_t tmp)
 {
 #if defined (DEBUG_OP)
     target_ulong sav = T0;
 #endif
-    uint32_t tmp;
 
-    tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
     /* XXX: this is valid only in big-endian mode
      *      should be reverted for little-endian...
      */
-    switch (T0 & 3) {
+    switch (GET_LMASK(T0)) {
     case 0:
         T0 = (tmp >> 24) | (T1 & 0xFFFFFF00);
         break;
@@ -66,21 +68,19 @@ void glue(do_lwr, MEMSUFFIX) (void)
     RETURN();
 }
 
-void glue(do_swl, MEMSUFFIX) (void)
+uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp)
 {
 #if defined (DEBUG_OP)
     target_ulong sav;
 #endif
-    uint32_t tmp;
 
-    tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
 #if defined (DEBUG_OP)
     sav = tmp;
 #endif
     /* XXX: this is valid only in big-endian mode
      *      should be reverted for little-endian...
      */
-    switch (T0 & 3) {
+    switch (GET_LMASK(T0)) {
     case 0:
         tmp = T1;
         break;
@@ -94,7 +94,6 @@ void glue(do_swl, MEMSUFFIX) (void)
         tmp = (tmp & 0xFFFFFF00) | (T1 >> 24);
         break;
     }
-    glue(stl, MEMSUFFIX)(T0 & ~3, tmp);
 #if defined (DEBUG_OP)
     if (logfile) {
         fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
@@ -102,23 +101,22 @@ void glue(do_swl, MEMSUFFIX) (void)
     }
 #endif
     RETURN();
+    return tmp;
 }
 
-void glue(do_swr, MEMSUFFIX) (void)
+uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp)
 {
 #if defined (DEBUG_OP)
     target_ulong sav;
 #endif
-    uint32_t tmp;
 
-    tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
 #if defined (DEBUG_OP)
     sav = tmp;
 #endif
     /* XXX: this is valid only in big-endian mode
      *      should be reverted for little-endian...
      */
-    switch (T0 & 3) {
+    switch (GET_LMASK(T0)) {
     case 0:
         tmp = (tmp & 0x00FFFFFF) | (T1 << 24);
         break;
@@ -132,7 +130,6 @@ void glue(do_swr, MEMSUFFIX) (void)
         tmp = T1;
         break;
     }
-    glue(stl, MEMSUFFIX)(T0 & ~3, tmp);
 #if defined (DEBUG_OP)
     if (logfile) {
         fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
@@ -140,4 +137,5 @@ void glue(do_swr, MEMSUFFIX) (void)
     }
 #endif
     RETURN();
+    return tmp;
 }
index bbb322d..7fcfc24 100644 (file)
@@ -67,28 +67,35 @@ void glue(op_sw, MEMSUFFIX) (void)
     RETURN();
 }
 
-/* "half" load and stores */
+/* "half" load and stores.  We must do the memory access inline,
+   or fault handling won't work.  */
 void glue(op_lwl, MEMSUFFIX) (void)
 {
-    CALL_FROM_TB0(glue(do_lwl, MEMSUFFIX));
+    uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
+    CALL_FROM_TB1(glue(do_lwl, MEMSUFFIX), tmp);
     RETURN();
 }
 
 void glue(op_lwr, MEMSUFFIX) (void)
 {
-    CALL_FROM_TB0(glue(do_lwr, MEMSUFFIX));
+    uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
+    CALL_FROM_TB1(glue(do_lwr, MEMSUFFIX), tmp);
     RETURN();
 }
 
 void glue(op_swl, MEMSUFFIX) (void)
 {
-    CALL_FROM_TB0(glue(do_swl, MEMSUFFIX));
+    uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
+    tmp = CALL_FROM_TB1(glue(do_swl, MEMSUFFIX), tmp);
+    glue(stl, MEMSUFFIX)(T0 & ~3, tmp);
     RETURN();
 }
 
 void glue(op_swr, MEMSUFFIX) (void)
 {
-    CALL_FROM_TB0(glue(do_swr, MEMSUFFIX));
+    uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
+    tmp = CALL_FROM_TB1(glue(do_swr, MEMSUFFIX), tmp);
+    glue(stl, MEMSUFFIX)(T0 & ~3, tmp);
     RETURN();
 }
 
index 7055775..418a7af 100644 (file)
 #include "exec-all.h"
 #include "disas.h"
 
-#define MIPS_DEBUG_DISAS
+//#define MIPS_DEBUG_DISAS
 //#define MIPS_SINGLE_STEP
 
+#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"
@@ -332,17 +338,25 @@ static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
     }
 }
 
-static inline void generate_exception (DisasContext *ctx, int excp)
+static inline void generate_exception_err (DisasContext *ctx, int excp, int err)
 {
 #if defined MIPS_DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_IN_ASM)
             fprintf(logfile, "%s: raise exception %d\n", __func__, excp);
 #endif
     save_cpu_state(ctx, 1);
-    gen_op_raise_exception(excp);
+    if (err == 0)
+        gen_op_raise_exception(excp);
+    else
+        gen_op_raise_exception_err(excp, err);
     ctx->bstate = BS_EXCP;
 }
 
+static inline void generate_exception (DisasContext *ctx, int excp)
+{
+    generate_exception_err (ctx, excp, 0);
+}
+
 #if defined(CONFIG_USER_ONLY)
 #define op_ldst(name)        gen_op_##name##_raw()
 #define OP_LD_TABLE(width)
@@ -922,6 +936,25 @@ static void gen_trap (DisasContext *ctx, uint16_t opc,
     ctx->bstate = BS_STOP;
 }
 
+static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+{
+    TranslationBlock *tb;
+    tb = ctx->tb;
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
+        if (n == 0)
+            gen_op_goto_tb0(TBPARAM(tb));
+        else
+            gen_op_goto_tb1(TBPARAM(tb));
+        gen_op_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();
+    }
+}
+
 /* Branches (before delay slot) */
 static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
                                 int rs, int rt, int32_t offset)
@@ -995,47 +1028,54 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
         case OPC_BLEZ:    /* 0 <= 0          */
         case OPC_BLEZL:   /* 0 <= 0 likely   */
             /* Always take */
-            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
+            ctx->hflags |= MIPS_HFLAG_B;
             MIPS_DEBUG("balways");
             break;
         case OPC_BGEZAL:  /* 0 >= 0          */
         case OPC_BGEZALL: /* 0 >= 0 likely   */
             /* Always take and link */
             blink = 31;
-            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
+            ctx->hflags |= MIPS_HFLAG_B;
             MIPS_DEBUG("balways and link");
             break;
         case OPC_BNE:     /* rx != rx        */
         case OPC_BGTZ:    /* 0 > 0           */
         case OPC_BLTZ:    /* 0 < 0           */
-        case OPC_BLTZAL:  /* 0 < 0           */
             /* Treated as NOP */
             MIPS_DEBUG("bnever (NOP)");
             return;
+        case OPC_BLTZAL:  /* 0 < 0           */
+            gen_op_set_T0(ctx->pc + 8);
+            gen_op_store_T0_gpr(31);
+            return;
+        case OPC_BLTZALL: /* 0 < 0 likely */
+            gen_op_set_T0(ctx->pc + 8);
+            gen_op_store_T0_gpr(31);
+            gen_goto_tb(ctx, 0, ctx->pc + 4);
+            return;
         case OPC_BNEL:    /* rx != rx likely */
         case OPC_BGTZL:   /* 0 > 0 likely */
-        case OPC_BLTZALL: /* 0 < 0 likely */
         case OPC_BLTZL:   /* 0 < 0 likely */
             /* Skip the instruction in the delay slot */
             MIPS_DEBUG("bnever and skip");
-            gen_op_branch((long)ctx->tb, ctx->pc + 4);
+            gen_goto_tb(ctx, 0, ctx->pc + 4);
             return;
         case OPC_J:
-            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
+            ctx->hflags |= MIPS_HFLAG_B;
             MIPS_DEBUG("j %08x", btarget);
             break;
         case OPC_JAL:
             blink = 31;
-            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_B;
+            ctx->hflags |= MIPS_HFLAG_B;
             MIPS_DEBUG("jal %08x", btarget);
             break;
         case OPC_JR:
-            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR;
+            ctx->hflags |= MIPS_HFLAG_BR;
             MIPS_DEBUG("jr %s", regnames[rs]);
             break;
         case OPC_JALR:
             blink = rt;
-            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BR;
+            ctx->hflags |= MIPS_HFLAG_BR;
             MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
             break;
         default:
@@ -1112,14 +1152,14 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
             blink = 31;
             MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget);
         not_likely:
-            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BC;
+            ctx->hflags |= MIPS_HFLAG_BC;
             break;
         case OPC_BLTZALL:
             gen_op_ltz();
             blink = 31;
             MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget);
         likely:
-            ctx->hflags |= MIPS_HFLAG_DS | MIPS_HFLAG_BL;
+            ctx->hflags |= MIPS_HFLAG_BL;
             break;
         }
         gen_op_set_bcond();
@@ -1146,7 +1186,7 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
         if (loglevel & CPU_LOG_TB_IN_ASM) {
             fprintf(logfile, "CP0 is not usable\n");
         }
-        gen_op_raise_exception_err(EXCP_CpU, 0);
+        generate_exception_err (ctx, EXCP_CpU, 0);
         return;
     }
     switch (opc) {
@@ -1204,7 +1244,15 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
             ctx->bstate = BS_EXCP;
         }
         break;
-    /* XXX: TODO: WAIT */
+    case OPC_WAIT:
+        opn = "wait";
+        /* If we get an exception, we want to restart at next instruction */
+        ctx->pc += 4;
+        save_cpu_state(ctx, 1);
+        ctx->pc -= 4;
+        gen_op_wait();
+        ctx->bstate = BS_EXCP;
+        break;
     default:
         if (loglevel & CPU_LOG_TB_IN_ASM) {
             fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n",
@@ -1255,6 +1303,16 @@ static void gen_arith64 (DisasContext *ctx, uint16_t opc)
 
 #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)
 {
     int32_t offset;
@@ -1262,12 +1320,10 @@ static void decode_opc (DisasContext *ctx)
     uint16_t op, op1;
     int16_t imm;
 
-    if ((ctx->hflags & MIPS_HFLAG_DS) &&
-        (ctx->hflags & MIPS_HFLAG_BL)) {
+    if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
         /* Handle blikely not taken case */
         MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
-        gen_op_blikely((long)ctx->tb, ctx->pc + 4,
-                       ctx->hflags & ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS));
+        gen_blikely(ctx);
     }
     op = ctx->opcode >> 26;
     rs = ((ctx->opcode >> 21) & 0x1F);
@@ -1320,9 +1376,16 @@ static void decode_opc (DisasContext *ctx)
         case 0x05:          /* Pmon entry point */
             gen_op_pmon((ctx->opcode >> 6) & 0x1F);
             break;
-#if defined (MIPS_HAS_MOVCI)
+
         case 0x01:          /* MOVCI */
+#if defined (MIPS_HAS_MOVCI)
+            /* XXX */
+#else
+            /* Not implemented */
+            generate_exception_err (ctx, EXCP_CpU, 1);
 #endif
+            break;
+
 #if defined (TARGET_MIPS64)
         case 0x14: /* MIPS64 specific opcodes */
         case 0x16:
@@ -1397,7 +1460,7 @@ static void decode_opc (DisasContext *ctx)
             gen_cp0(ctx, op1 | EXT_CP0, rt, rd);
             break;
         default:
-            gen_cp0(ctx, (ctx->opcode & 0x1F) | EXT_CP0, rt, rd);
+            gen_cp0(ctx, (ctx->opcode & 0x3F) | EXT_CP0, rt, rd);
             break;
         }
         break;
@@ -1426,23 +1489,35 @@ static void decode_opc (DisasContext *ctx)
         break;
     case 0x3F: /* HACK */
         break;
+
+    /* Floating point.  */
+    case 0x31: /* LWC1 */
+    case 0x35: /* LDC1 */
+    case 0x39: /* SWC1 */
+    case 0x3D: /* SDC1 */
+    case 0x11:          /* CP1 opcode */
 #if defined(MIPS_USES_FPU)
-    case 0x31 ... 0x32: /* Floating point load/store */
-    case 0x35 ... 0x36:
-    case 0x3A ... 0x3B:
-    case 0x3D ... 0x3E:
-        /* Not implemented */
         /* XXX: not correct */
+#else
+        generate_exception_err(ctx, EXCP_CpU, 1);
 #endif
-    case 0x11:          /* CP1 opcode */
-        /* Not implemented */
-        /* XXX: not correct */
+        break;
+
+    /* COP2.  */
+    case 0x32: /* LWC2 */
+    case 0x36: /* LDC2 */
+    case 0x3A: /* SWC2 */
+    case 0x3E: /* SDC2 */
     case 0x12:          /* CP2 opcode */
         /* Not implemented */
-        /* XXX: not correct */
+        generate_exception_err(ctx, EXCP_CpU, 2);
+        break;
+
     case 0x13:          /* CP3 opcode */
         /* Not implemented */
-        /* XXX: not correct */
+        generate_exception_err(ctx, EXCP_CpU, 3);
+        break;
+
 #if defined (TARGET_MIPS64)
     case 0x18 ... 0x1B:
     case 0x27:
@@ -1456,38 +1531,39 @@ static void decode_opc (DisasContext *ctx)
 #endif
     case 0x1E:
         /* ASE specific */
-#if defined (MIPS_HAS_LSC)
-    case 0x31: /* LWC1 */
-    case 0x32: /* LWC2 */
-    case 0x35: /* SDC1 */
-    case 0x36: /* SDC2 */
-#endif
     default:            /* Invalid */
         MIPS_INVAL("");
         generate_exception(ctx, EXCP_RI);
         break;
     }
-    if (ctx->hflags & MIPS_HFLAG_DS) {
+    if (ctx->hflags & MIPS_HFLAG_BMASK) {
         int hflags = ctx->hflags;
         /* Branches completion */
-        ctx->hflags &= ~(MIPS_HFLAG_BMASK | MIPS_HFLAG_DS);
+        ctx->hflags &= ~MIPS_HFLAG_BMASK;
         ctx->bstate = BS_BRANCH;
         save_cpu_state(ctx, 0);
         switch (hflags & MIPS_HFLAG_BMASK) {
         case MIPS_HFLAG_B:
             /* unconditional branch */
             MIPS_DEBUG("unconditional branch");
-            gen_op_branch((long)ctx->tb, ctx->btarget);
+            gen_goto_tb(ctx, 0, ctx->btarget);
             break;
         case MIPS_HFLAG_BL:
             /* blikely taken case */
             MIPS_DEBUG("blikely branch taken");
-            gen_op_branch((long)ctx->tb, ctx->btarget);
+            gen_goto_tb(ctx, 0, ctx->btarget);
             break;
         case MIPS_HFLAG_BC:
             /* Conditional branch */
             MIPS_DEBUG("conditional branch");
-            gen_op_bcond((long)ctx->tb, ctx->btarget, ctx->pc + 4);
+            {
+              int l1;
+              l1 = gen_new_label();
+              gen_op_jnz_T2(l1);
+              gen_goto_tb(ctx, 1, ctx->pc + 4);
+              gen_set_label(l1);
+              gen_goto_tb(ctx, 0, ctx->btarget);
+            }
             break;
         case MIPS_HFLAG_BR:
             /* unconditional branch to register */
@@ -1509,15 +1585,20 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     uint16_t *gen_opc_end;
     int j, lj = -1;
 
+    if (search_pc && loglevel)
+       fprintf (logfile, "search pc %d\n", search_pc);
+
     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.saved_pc = -1;
     ctx.tb = tb;
     ctx.bstate = BS_NONE;
-    /* Restore delay slot state */
-    ctx.hflags = env->hflags;
+    /* 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();
@@ -1539,42 +1620,65 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
 #ifdef DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_CPU) {
         fprintf(logfile, "------------------------------------------------\n");
+        /* FIXME: This may print out stale hflags from env... */
         cpu_dump_state(env, logfile, fprintf, 0);
     }
 #endif
 #if defined MIPS_DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_IN_ASM)
-        fprintf(logfile, "\ntb %p super %d cond %04x %04x\n",
-                tb, ctx.mem_idx, ctx.hflags, env->hflags);
+        fprintf(logfile, "\ntb %p super %d cond %04x\n",
+                tb, ctx.mem_idx, ctx.hflags);
 #endif
     while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
+        if (env->nb_breakpoints > 0) {
+            for(j = 0; j < env->nb_breakpoints; j++) {
+                if (env->breakpoints[j] == ctx.pc) {
+                    save_cpu_state(ctxp, 1);
+                    ctx.bstate = BS_BRANCH;
+                    gen_op_debug();
+                    goto done_generating;
+                }
+            }
+        }
+
         if (search_pc) {
             j = gen_opc_ptr - gen_opc_buf;
-            save_cpu_state(ctxp, 1);
             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;
             }
+            gen_opc_pc[lj] = ctx.pc;
+            gen_opc_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK;
+            gen_opc_instr_start[lj] = 1;
         }
         ctx.opcode = ldl_code(ctx.pc);
         decode_opc(&ctx);
         ctx.pc += 4;
+
+        if (env->singlestep_enabled)
+            break;
+
         if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
             break;
+
 #if defined (MIPS_SINGLE_STEP)
         break;
 #endif
     }
-    if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
+    if (env->singlestep_enabled) {
+        save_cpu_state(ctxp, ctx.bstate == BS_NONE);
+        gen_op_debug();
+        goto done_generating;
+    }
+    else if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
         save_cpu_state(ctxp, 0);
-        gen_op_branch((long)ctx.tb, ctx.pc);
+        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) {
         j = gen_opc_ptr - gen_opc_buf;
@@ -1653,10 +1757,10 @@ CPUMIPSState *cpu_mips_init (void)
 {
     CPUMIPSState *env;
 
-    cpu_exec_init();
     env = qemu_mallocz(sizeof(CPUMIPSState));
     if (!env)
         return NULL;
+    cpu_exec_init(env);
     tlb_flush(env, 1);
     /* Minimal init */
     env->PC = 0xBFC00000;
@@ -1681,8 +1785,8 @@ CPUMIPSState *cpu_mips_init (void)
     env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
     env->CP0_PRid = MIPS_CPU;
     env->exception_index = EXCP_NONE;
-
-    cpu_single_env = env;
-
+#if defined(CONFIG_USER_ONLY)
+    env->hflags |= MIPS_HFLAG_UM;
+#endif
     return env;
 }
index 8dd9cc1..88d9135 100644 (file)
@@ -493,19 +493,12 @@ struct CPUPPCState {
     /* floating point status and control register */
     uint8_t fpscr[8];
 
-    /* soft mmu support */
-    /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */
-    CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
-    CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
+    CPU_COMMON
+
+    int halted; /* TRUE if the CPU is in suspend state */
+
     int access_type; /* when a memory exception occurs, the access
                         type is stored here */
-    /* in order to avoid passing too many arguments to the memory
-       write helpers, we store some rarely used information in the CPU
-       context) */
-    unsigned long mem_write_pc; /* host pc at which the memory was
-                                   written */
-    unsigned long mem_write_vaddr; /* target virtual addr at which the
-                                      memory was written */
 
     /* MMU context */
     /* Address space register */
@@ -564,22 +557,13 @@ struct CPUPPCState {
     /* Those resources are used only in Qemu core */
     jmp_buf jmp_env;
     int user_mode_only; /* user mode only simulation */
-    struct TranslationBlock *current_tb; /* currently executing TB */
     uint32_t hflags;
 
-    /* ice debug support */
-    target_ulong breakpoints[MAX_BREAKPOINTS];
-    int nb_breakpoints;
-    int singlestep_enabled; /* XXX: should use CPU single step mode instead */
-
     /* Power management */
     int power_mode;
 
     /* temporary hack to handle OSI calls (only used if non NULL) */
     int (*osi_call)(struct CPUPPCState *env);
-
-    /* user data */
-    void *opaque;
 };
 
 /*****************************************************************************/
index 9e89880..3ef0968 100644 (file)
@@ -51,73 +51,8 @@ static inline uint32_t rotl (uint32_t i, int n)
     return ((i << n) | (i >> (32 - n)));
 }
 
-/* XXX: move that to a generic header */
 #if !defined(CONFIG_USER_ONLY)
-
-#define ldul_user ldl_user
-#define ldul_kernel ldl_kernel
-
-#define ACCESS_TYPE 0
-#define MEMSUFFIX _kernel
-#define DATA_SIZE 1
-#include "softmmu_header.h"
-
-#define DATA_SIZE 2
-#include "softmmu_header.h"
-
-#define DATA_SIZE 4
-#include "softmmu_header.h"
-
-#define DATA_SIZE 8
-#include "softmmu_header.h"
-#undef ACCESS_TYPE
-#undef MEMSUFFIX
-
-#define ACCESS_TYPE 1
-#define MEMSUFFIX _user
-#define DATA_SIZE 1
-#include "softmmu_header.h"
-
-#define DATA_SIZE 2
-#include "softmmu_header.h"
-
-#define DATA_SIZE 4
-#include "softmmu_header.h"
-
-#define DATA_SIZE 8
-#include "softmmu_header.h"
-#undef ACCESS_TYPE
-#undef MEMSUFFIX
-
-/* these access are slower, they must be as rare as possible */
-#define ACCESS_TYPE 2
-#define MEMSUFFIX _data
-#define DATA_SIZE 1
-#include "softmmu_header.h"
-
-#define DATA_SIZE 2
-#include "softmmu_header.h"
-
-#define DATA_SIZE 4
-#include "softmmu_header.h"
-
-#define DATA_SIZE 8
-#include "softmmu_header.h"
-#undef ACCESS_TYPE
-#undef MEMSUFFIX
-
-#define ldub(p) ldub_data(p)
-#define ldsb(p) ldsb_data(p)
-#define lduw(p) lduw_data(p)
-#define ldsw(p) ldsw_data(p)
-#define ldl(p) ldl_data(p)
-#define ldq(p) ldq_data(p)
-
-#define stb(p, v) stb_data(p, v)
-#define stw(p, v) stw_data(p, v)
-#define stl(p, v) stl_data(p, v)
-#define stq(p, v) stq_data(p, v)
-
+#include "softmmu_exec.h"
 #endif /* !defined(CONFIG_USER_ONLY) */
 
 void do_raise_exception_err (uint32_t exception, int error_code);
index c9693c8..3f7a708 100644 (file)
 /*****************************************************************************/
 /* PowerPC MMU emulation */
 
+#if defined(CONFIG_USER_ONLY) 
+int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+                              int is_user, int is_softmmu)
+{
+    int exception, error_code;
+    
+    if (rw == 2) {
+        exception = EXCP_ISI;
+        error_code = 0;
+    } else {
+        exception = EXCP_DSI;
+        error_code = 0;
+        if (rw)
+            error_code |= 0x02000000;
+        env->spr[SPR_DAR] = address;
+        env->spr[SPR_DSISR] = error_code;
+    }
+    env->exception_index = exception;
+    env->error_code = error_code;
+    return 1;
+}
+target_ulong 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)
@@ -355,8 +381,8 @@ static int get_segment (CPUState *env, uint32_t *real, int *prot,
     return ret;
 }
 
-int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
-                          uint32_t address, int rw, int access_type)
+static int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
+                                 uint32_t address, int rw, int access_type)
 {
     int ret;
 #if 0
@@ -387,12 +413,6 @@ int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
     return ret;
 }
 
-#if defined(CONFIG_USER_ONLY) 
-target_ulong 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)
 {
     uint32_t phys_addr;
@@ -402,7 +422,6 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
         return -1;
     return phys_addr;
 }
-#endif
 
 /* Perform address translation */
 int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
@@ -523,6 +542,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
     }
     return ret;
 }
+#endif
 
 /*****************************************************************************/
 /* BATs management */
@@ -786,7 +806,9 @@ void do_compute_hflags (CPUPPCState *env)
 }
 
 void do_store_msr (CPUPPCState *env, target_ulong value)
-    {
+{
+    int enter_pm;
+
     value &= env->msr_mask;
     if (((value >> MSR_IR) & 1) != msr_ir ||
         ((value >> MSR_DR) & 1) != msr_dr) {
@@ -826,6 +848,22 @@ void do_store_msr (CPUPPCState *env, target_ulong value)
     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)
+            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();
+    }
 }
 
 float64 do_load_fpscr (CPUPPCState *env)
@@ -1416,15 +1454,5 @@ void do_interrupt (CPUState *env)
     /* Jump to handler */
     env->nip = excp;
     env->exception_index = EXCP_NONE;
-#if 0
-    /* ensure that no TB jump will be modified as
-       the program flow was changed */
-#ifdef __sparc__
-    tmp_T0 = 0;
-#else
-    T0 = 0;
-#endif
-#endif
-    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
 }
 #endif /* !CONFIG_USER_ONLY */
index 0e37119..4b0af55 100644 (file)
@@ -451,9 +451,14 @@ PPC_OP(setlr)
     regs->lr = PARAM1;
 }
 
-PPC_OP(b)
+PPC_OP(goto_tb0)
 {
-    JUMP_TB(b1, PARAM1, 0, PARAM2);
+    GOTO_TB(op_goto_tb0, PARAM1, 0);
+}
+
+PPC_OP(goto_tb1)
+{
+    GOTO_TB(op_goto_tb1, PARAM1, 1);
 }
 
 PPC_OP(b_T1)
@@ -461,13 +466,10 @@ PPC_OP(b_T1)
     regs->nip = T1 & ~3;
 }
 
-PPC_OP(btest) 
+PPC_OP(jz_T0)
 {
-    if (T0) {
-        JUMP_TB(btest, PARAM1, 0, PARAM2);
-    } else {
-        JUMP_TB(btest, PARAM1, 1, PARAM3);
-    }
+    if (!T0)
+        GOTO_LABEL_PARAM(1);
     RETURN();
 }
 
index 70f8863..3bc6aa3 100644 (file)
 //#define DO_SINGLE_STEP
 //#define PPC_DEBUG_DISAS
 
+#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"
@@ -171,17 +177,16 @@ RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
 #define RET_PRIVREG(ctx)                                                      \
 RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
 
-#define RET_MTMSR(ctx)                                                        \
-RET_EXCP((ctx), EXCP_MTMSR, 0)
-
+/* Stop translation */
 static inline void RET_STOP (DisasContext *ctx)
 {
-    RET_EXCP(ctx, EXCP_MTMSR, 0);
+    gen_op_update_nip((ctx)->nip);
+    ctx->exception = EXCP_MTMSR;
 }
 
+/* No need to update nip here, as execution flow will change */
 static inline void RET_CHG_FLOW (DisasContext *ctx)
 {
-    gen_op_raise_exception_err(EXCP_MTMSR, 0);
     ctx->exception = EXCP_MTMSR;
 }
 
@@ -1721,6 +1726,27 @@ GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
 
 /***                                Branch                                 ***/
 
+static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+{
+    TranslationBlock *tb;
+    tb = ctx->tb;
+    if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
+        if (n == 0)
+            gen_op_goto_tb0(TBPARAM(tb));
+        else
+            gen_op_goto_tb1(TBPARAM(tb));
+        gen_op_set_T1(dest);
+        gen_op_b_T1();
+        gen_op_set_T0((long)tb + n);
+        gen_op_exit_tb();
+    } else {
+        gen_op_set_T1(dest);
+        gen_op_b_T1();
+        gen_op_set_T0(0);
+        gen_op_exit_tb();
+    }
+}
+
 /* b ba bl bla */
 GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
 {
@@ -1736,7 +1762,7 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
     if (LK(ctx->opcode)) {
         gen_op_setlr(ctx->nip);
     }
-    gen_op_b((long)ctx->tb, target);
+    gen_goto_tb(ctx, 0, target);
     ctx->exception = EXCP_BRANCH;
 }
 
@@ -1787,7 +1813,7 @@ static inline void gen_bcond(DisasContext *ctx, int type)
         case 4:                                                               
         case 6:                                                               
             if (type == BCOND_IM) {
-                gen_op_b((long)ctx->tb, target);
+                gen_goto_tb(ctx, 0, target);
             } else {
                 gen_op_b_T1();
             }
@@ -1827,7 +1853,11 @@ static inline void gen_bcond(DisasContext *ctx, int type)
         }                                                                     
     }                                                                         
     if (type == BCOND_IM) {
-        gen_op_btest((long)ctx->tb, target, ctx->nip);
+        int l1 = gen_new_label();
+        gen_op_jz_T0(l1);
+        gen_goto_tb(ctx, 0, target);
+        gen_set_label(l1);
+        gen_goto_tb(ctx, 1, ctx->nip);
     } else {
         gen_op_btest_T1(ctx->nip);
     }
@@ -2020,11 +2050,19 @@ static inline void gen_op_mfspr (DisasContext *ctx)
             gen_op_store_T0_gpr(rD(ctx->opcode));
         } else {
             /* Privilege exception */
+            if (loglevel) {
+                fprintf(logfile, "Trying to read priviledged spr %d %03x\n",
+                        sprn, sprn);
+            }
             printf("Trying to read priviledged spr %d %03x\n", sprn, sprn);
         RET_PRIVREG(ctx);
         }
     } else {
         /* Not defined */
+        if (loglevel) {
+            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);
     }
@@ -2059,10 +2097,11 @@ GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
         RET_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_MTMSR(ctx);
+    RET_CHG_FLOW(ctx);
 #endif
 }
 
@@ -2084,11 +2123,19 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
             (*write_cb)(ctx, sprn);
         } else {
             /* Privilege exception */
+            if (loglevel) {
+                fprintf(logfile, "Trying to write priviledged spr %d %03x\n",
+                        sprn, sprn);
+            }
             printf("Trying to write priviledged spr %d %03x\n", sprn, sprn);
         RET_PRIVREG(ctx);
     }
     } else {
         /* Not defined */
+        if (loglevel) {
+            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);
     }
@@ -2247,6 +2294,7 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
     }
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_store_sr(SR(ctx->opcode));
+    RET_STOP(ctx);
 #endif
 }
 
@@ -2263,6 +2311,7 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_load_gpr_T1(rB(ctx->opcode));
     gen_op_store_srin();
+    RET_STOP(ctx);
 #endif
 }
 
@@ -2281,7 +2330,7 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
         return;
     }
     gen_op_tlbia();
-    RET_MTMSR(ctx);
+    RET_STOP(ctx);
 #endif
 }
 
@@ -2297,7 +2346,7 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM)
     }
     gen_op_load_gpr_T0(rB(ctx->opcode));
     gen_op_tlbie();
-    RET_MTMSR(ctx);
+    RET_STOP(ctx);
 #endif
 }
 
@@ -2314,7 +2363,7 @@ GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM)
     /* This has no effect: it should ensure that all previous
      * tlbie have completed
      */
-    RET_MTMSR(ctx);
+    RET_STOP(ctx);
 #endif
 }
 
@@ -2459,6 +2508,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     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.nip = pc_start;
     ctx.tb = tb;
     ctx.exception = EXCP_NONE;
@@ -2575,7 +2625,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
 #endif
     }
     if (ctx.exception == EXCP_NONE) {
-        gen_op_b((unsigned long)ctx.tb, ctx.nip);
+        gen_goto_tb(&ctx, 0, ctx.nip);
     } else if (ctx.exception != EXCP_BRANCH) {
         gen_op_set_T0(0);
     }
@@ -2609,7 +2659,7 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
     }
     if (loglevel & CPU_LOG_TB_IN_ASM) {
         fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
-       target_disas(logfile, pc_start, ctx.nip - pc_start, 0);
+       target_disas(logfile, pc_start, ctx.nip - pc_start, msr_le);
         fprintf(logfile, "\n");
     }
     if (loglevel & CPU_LOG_TB_OP) {
index 624527d..012c34f 100644 (file)
@@ -1081,11 +1081,10 @@ CPUPPCState *cpu_ppc_init(void)
 {
     CPUPPCState *env;
 
-    cpu_exec_init();
-
     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 */
@@ -1101,7 +1100,6 @@ CPUPPCState *cpu_ppc_init(void)
 #endif
     do_compute_hflags(env);
     env->reserve = -1;
-    cpu_single_env = env;
     return env;
 }
 
index 999d5d7..28efab7 100644 (file)
@@ -166,21 +166,12 @@ typedef struct CPUSPARCState {
     int exception_index;
     int interrupt_index;
     int interrupt_request;
-    struct TranslationBlock *current_tb;
-    void *opaque;
+    int halted;
     /* NOTE: we allow 8 more registers to handle wrapping */
     target_ulong regbase[NWINDOWS * 16 + 8];
 
-    /* in order to avoid passing too many arguments to the memory
-       write helpers, we store some rarely used information in the CPU
-       context) */
-    unsigned long mem_write_pc; /* host pc at which the memory was
-                                   written */
-    target_ulong mem_write_vaddr; /* target virtual addr at which the
-                                      memory was written */
-    /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */
-    CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
-    CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
+    CPU_COMMON
+
     /* MMU regs */
 #if defined(TARGET_SPARC64)
     uint64_t lsu;
@@ -222,12 +213,6 @@ typedef struct CPUSPARCState {
 #if !defined(TARGET_SPARC64) && !defined(reg_T2)
     target_ulong t2;
 #endif
-
-    /* ice debug support */
-    target_ulong breakpoints[MAX_BREAKPOINTS];
-    int nb_breakpoints;
-    int singlestep_enabled; /* XXX: should use CPU single step mode instead */
-
 } CPUSPARCState;
 #if defined(TARGET_SPARC64)
 #define GET_FSR32(env) (env->fsr & 0xcfc1ffff)
index 942b811..1b67ef4 100644 (file)
@@ -83,75 +83,15 @@ void do_rdpsr();
 
 /* XXX: move that to a generic header */
 #if !defined(CONFIG_USER_ONLY)
-
-#define ldul_user ldl_user
-#define ldul_kernel ldl_kernel
-
-#define ACCESS_TYPE 0
-#define MEMSUFFIX _kernel
-#define DATA_SIZE 1
-#include "softmmu_header.h"
-
-#define DATA_SIZE 2
-#include "softmmu_header.h"
-
-#define DATA_SIZE 4
-#include "softmmu_header.h"
-
-#define DATA_SIZE 8
-#include "softmmu_header.h"
-#undef ACCESS_TYPE
-#undef MEMSUFFIX
-
-#define ACCESS_TYPE 1
-#define MEMSUFFIX _user
-#define DATA_SIZE 1
-#include "softmmu_header.h"
-
-#define DATA_SIZE 2
-#include "softmmu_header.h"
-
-#define DATA_SIZE 4
-#include "softmmu_header.h"
-
-#define DATA_SIZE 8
-#include "softmmu_header.h"
-#undef ACCESS_TYPE
-#undef MEMSUFFIX
-
-/* these access are slower, they must be as rare as possible */
-#define ACCESS_TYPE 2
-#define MEMSUFFIX _data
-#define DATA_SIZE 1
-#include "softmmu_header.h"
-
-#define DATA_SIZE 2
-#include "softmmu_header.h"
-
-#define DATA_SIZE 4
-#include "softmmu_header.h"
-
-#define DATA_SIZE 8
-#include "softmmu_header.h"
-#undef ACCESS_TYPE
-#undef MEMSUFFIX
-
-#define ldub(p) ldub_data(p)
-#define ldsb(p) ldsb_data(p)
-#define lduw(p) lduw_data(p)
-#define ldsw(p) ldsw_data(p)
-#define ldl(p) ldl_data(p)
-#define ldq(p) ldq_data(p)
-
-#define stb(p, v) stb_data(p, v)
-#define stw(p, v) stw_data(p, v)
-#define stl(p, v) stl_data(p, v)
-#define stq(p, v) stq_data(p, v)
-
+#include "softmmu_exec.h"
 #endif /* !defined(CONFIG_USER_ONLY) */
 
 static inline void env_to_regs(void)
 {
+#if defined(reg_REGWPTR)
+    REGWPTR = env->regbase + (env->cwp * 16);
+    env->regwptr = REGWPTR;
+#endif
 }
 
 static inline void regs_to_env(void)
index 78a033b..d011de7 100644 (file)
@@ -75,10 +75,27 @@ static const int access_table[8][8] = {
     { 2, 2, 2, 0, 2, 2, 2, 0 }
 };
 
-/* 1 = write OK */
-static const int rw_table[2][8] = {
-    { 0, 1, 0, 1, 0, 1, 0, 1 },
-    { 0, 1, 0, 1, 0, 0, 0, 0 }
+static const int perm_table[2][8] = {
+    {
+        PAGE_READ,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+        PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC
+    },
+    {
+        PAGE_READ,
+        PAGE_READ | PAGE_WRITE,
+        PAGE_READ | PAGE_EXEC,
+        PAGE_READ | PAGE_WRITE | PAGE_EXEC,
+        PAGE_EXEC,
+        PAGE_READ,
+        0,
+        0,
+    }
 };
 
 int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot,
@@ -95,7 +112,7 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot
     virt_addr = address & TARGET_PAGE_MASK;
     if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
        *physical = address;
-        *prot = PAGE_READ | PAGE_WRITE;
+        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
         return 0;
     }
 
@@ -177,12 +194,11 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot
        return error_code;
 
     /* the page can be put in the TLB */
-    *prot = PAGE_READ;
-    if (pde & PG_MODIFIED_MASK) {
+    *prot = perm_table[is_user][access_perms];
+    if (!(pde & PG_MODIFIED_MASK)) {
         /* only set write access if already dirty... otherwise wait
            for dirty access */
-       if (rw_table[is_user][access_perms])
-               *prot |= PAGE_WRITE;
+        *prot &= ~PAGE_WRITE;
     }
 
     /* Even if large ptes, we map only one 4KB page in the cache to
@@ -195,16 +211,18 @@ int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot
 int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                               int is_user, int is_softmmu)
 {
-    target_ulong virt_addr;
     target_phys_addr_t paddr;
     unsigned long 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) {
-       virt_addr = address & TARGET_PAGE_MASK;
-       vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
-       ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
+       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);
+#endif
+       ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
        return ret;
     }
 
@@ -219,8 +237,8 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
         // neverland. Fake/overridden mappings will be flushed when
         // switching to normal mode.
        vaddr = address & TARGET_PAGE_MASK;
-        prot = PAGE_READ | PAGE_WRITE;
-        ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
+        prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+        ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
        return ret;
     } else {
         if (rw & 2)
@@ -230,7 +248,107 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
         return 1;
     }
 }
-#else
+
+target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
+{
+    target_phys_addr_t pde_ptr;
+    uint32_t pde;
+
+    /* Context base + context number */
+    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
+    pde = ldl_phys(pde_ptr);
+
+    switch (pde & PTE_ENTRYTYPE_MASK) {
+    default:
+    case 0: /* Invalid */
+    case 2: /* PTE, maybe should not happen? */
+    case 3: /* Reserved */
+       return 0;
+    case 1: /* L1 PDE */
+       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);
+            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);
+                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;
+               }
+           }
+       }
+    }
+    return 0;
+}
+
+#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;
+    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]);
+    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);
+                       }
+                   }
+               }
+           }
+       }
+    }
+    printf("MMU dump ends\n");
+}
+#endif /* DEBUG_MMU */
+
+#else /* !TARGET_SPARC64 */
 /*
  * UltraSparc IIi I/DMMUs
  */
@@ -303,7 +421,7 @@ static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical
 
     if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */
        *physical = address;
-       *prot = PAGE_READ;
+       *prot = PAGE_EXEC;
         return 0;
     }
 
@@ -339,7 +457,7 @@ static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical
                return 1;
            }
            *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
-           *prot = PAGE_READ;
+           *prot = PAGE_EXEC;
            return 0;
        }
     }
@@ -375,128 +493,13 @@ int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
 #ifdef DEBUG_MMU
        printf("Translate at 0x%llx -> 0x%llx, vaddr 0x%llx\n", address, paddr, vaddr);
 #endif
-       ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
+       ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
        return ret;
     }
     // XXX
     return 1;
 }
 
-#endif
-#endif
-
-void memcpy32(target_ulong *dst, const target_ulong *src)
-{
-    dst[0] = src[0];
-    dst[1] = src[1];
-    dst[2] = src[2];
-    dst[3] = src[3];
-    dst[4] = src[4];
-    dst[5] = src[5];
-    dst[6] = src[6];
-    dst[7] = src[7];
-}
-
-#if !defined(TARGET_SPARC64)
-target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
-{
-    target_phys_addr_t pde_ptr;
-    uint32_t pde;
-
-    /* Context base + context number */
-    pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
-    pde = ldl_phys(pde_ptr);
-
-    switch (pde & PTE_ENTRYTYPE_MASK) {
-    default:
-    case 0: /* Invalid */
-    case 2: /* PTE, maybe should not happen? */
-    case 3: /* Reserved */
-       return 0;
-    case 1: /* L1 PDE */
-       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);
-            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);
-                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;
-               }
-           }
-       }
-    }
-    return 0;
-}
-
-#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;
-    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]);
-    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);
-                       }
-                   }
-               }
-           }
-       }
-    }
-    printf("MMU dump ends\n");
-}
-#endif
-#else
 #ifdef DEBUG_MMU
 void dump_mmu(CPUState *env)
 {
@@ -568,5 +571,19 @@ void dump_mmu(CPUState *env)
        }
     }
 }
-#endif
-#endif
+#endif /* DEBUG_MMU */
+
+#endif /* TARGET_SPARC64 */
+#endif /* !CONFIG_USER_ONLY */
+
+void memcpy32(target_ulong *dst, const target_ulong *src)
+{
+    dst[0] = src[0];
+    dst[1] = src[1];
+    dst[2] = src[2];
+    dst[3] = src[3];
+    dst[4] = src[4];
+    dst[5] = src[5];
+    dst[6] = src[6];
+    dst[7] = src[7];
+}
index f8b491a..67de62f 100644 (file)
@@ -379,7 +379,7 @@ void OPPROTO op_add_T1_T0_cc(void)
        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
        env->psr |= PSR_NEG;
-    if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
+    if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
        env->psr |= PSR_CARRY;
     if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) &
         ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
@@ -424,7 +424,7 @@ void OPPROTO op_addx_T1_T0_cc(void)
        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
        env->psr |= PSR_NEG;
-    if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
+    if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
        env->psr |= PSR_CARRY;
     if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) &
         ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
@@ -480,7 +480,7 @@ void OPPROTO op_sub_T1_T0_cc(void)
        env->xcc |= PSR_ZERO;
     if ((int64_t) T0 < 0)
        env->xcc |= PSR_NEG;
-    if (T0 < src1)
+    if (src1 < T1)
        env->xcc |= PSR_CARRY;
     if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63))
        env->xcc |= PSR_OVF;
@@ -525,7 +525,7 @@ void OPPROTO op_subx_T1_T0_cc(void)
        env->xcc |= PSR_ZERO;
     if ((int64_t) T0 < 0)
        env->xcc |= PSR_NEG;
-    if (T0 < src1)
+    if (src1 < T1)
        env->xcc |= PSR_CARRY;
     if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63))
        env->xcc |= PSR_OVF;
index 468bbb6..030b2f7 100644 (file)
@@ -221,6 +221,15 @@ void do_fcmpd_fcc3 (void)
 #undef FS
 #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
 void helper_ld_asi(int asi, int size, int sign)
 {
@@ -256,11 +265,22 @@ void helper_ld_asi(int asi, int size, int sign)
        }
        break;
     case 0x20 ... 0x2f: /* MMU passthrough */
-       cpu_physical_memory_read(T0, (void *) &ret, size);
-       if (size == 4)
-           tswap32s(&ret);
-        else if (size == 2)
-           tswap16s((uint16_t *)&ret);
+        switch(size) {
+        case 1:
+            ret = ldub_phys(T0);
+            break;
+        case 2:
+            ret = lduw_phys(T0 & ~1);
+            break;
+        default:
+        case 4:
+            ret = ldl_phys(T0 & ~3);
+            break;
+        case 8:
+           ret = ldl_phys(T0 & ~3);
+           T0 = ldl_phys((T0 + 4) & ~3);
+           break;
+        }
        break;
     default:
        ret = 0;
@@ -369,12 +389,22 @@ void helper_st_asi(int asi, int size, int sign)
        return;
     case 0x20 ... 0x2f: /* MMU passthrough */
        {
-           uint32_t temp = T1;
-           if (size == 4)
-               tswap32s(&temp);
-           else if (size == 2)
-               tswap16s((uint16_t *)&temp);
-           cpu_physical_memory_write(T0, (void *) &temp, size);
+            switch(size) {
+            case 1:
+                stb_phys(T0, T1);
+                break;
+            case 2:
+                stw_phys(T0 & ~1, T1);
+                break;
+            case 4:
+            default:
+                stl_phys(T0 & ~3, T1);
+                break;
+            case 8:
+                stl_phys(T0 & ~3, T1);
+                stl_phys((T0 + 4) & ~3, T2);
+                break;
+            }
        }
        return;
     default:
@@ -395,13 +425,21 @@ void helper_ld_asi(int asi, int size, int sign)
     case 0x14: // Bypass
     case 0x15: // Bypass, non-cacheable
        {
-           cpu_physical_memory_read(T0, (void *) &ret, size);
-           if (size == 8)
-               tswap64s(&ret);
-           if (size == 4)
-               tswap32s((uint32_t *)&ret);
-           else if (size == 2)
-               tswap16s((uint16_t *)&ret);
+            switch(size) {
+            case 1:
+                ret = ldub_phys(T0);
+                break;
+            case 2:
+                ret = lduw_phys(T0 & ~1);
+                break;
+            case 4:
+                ret = ldl_phys(T0 & ~3);
+                break;
+            default:
+            case 8:
+                ret = ldq_phys(T0 & ~7);
+                break;
+            }
            break;
        }
     case 0x04: // Nucleus
@@ -503,14 +541,21 @@ void helper_st_asi(int asi, int size, int sign)
     case 0x14: // Bypass
     case 0x15: // Bypass, non-cacheable
        {
-           target_ulong temp = T1;
-           if (size == 8)
-               tswap64s(&temp);
-           else if (size == 4)
-               tswap32s((uint32_t *)&temp);
-           else if (size == 2)
-               tswap16s((uint16_t *)&temp);
-           cpu_physical_memory_write(T0, (void *) &temp, size);
+            switch(size) {
+            case 1:
+                stb_phys(T0, T1);
+                break;
+            case 2:
+                stw_phys(T0 & ~1, T1);
+                break;
+            case 4:
+                stl_phys(T0 & ~3, T1);
+                break;
+            case 8:
+            default:
+                stq_phys(T0 & ~7, T1);
+                break;
+            }
        }
        return;
     case 0x04: // Nucleus
@@ -699,8 +744,8 @@ void helper_st_asi(int asi, int size, int sign)
        return;
     }
 }
-
 #endif
+#endif /* !CONFIG_USER_ONLY */
 
 #ifndef TARGET_SPARC64
 void helper_rett()
@@ -897,7 +942,7 @@ void do_interrupt(int intno)
 #endif
 #if !defined(CONFIG_USER_ONLY) 
     if (env->tl == MAXTL) {
-        cpu_abort(cpu_single_env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index);
+        cpu_abort(env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index);
        return;
     }
 #endif
@@ -951,7 +996,7 @@ void do_interrupt(int intno)
 #endif
 #if !defined(CONFIG_USER_ONLY) 
     if (env->psret == 0) {
-        cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index);
+        cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index);
        return;
     }
 #endif
index c2ba2e3..8a8620f 100644 (file)
@@ -561,6 +561,32 @@ static inline void gen_movl_npc_im(target_ulong npc)
 #endif
 }
 
+static inline void gen_goto_tb(DisasContext *s, int tb_num, 
+                               target_ulong pc, target_ulong npc)
+{
+    TranslationBlock *tb;
+
+    tb = s->tb;
+    if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) &&
+        (npc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK))  {
+        /* jump to same page: we can use a direct jump */
+        if (tb_num == 0)
+            gen_op_goto_tb0(TBPARAM(tb));
+        else
+            gen_op_goto_tb1(TBPARAM(tb));
+        gen_jmp_im(pc);
+        gen_movl_npc_im(npc);
+        gen_op_movl_T0_im((long)tb + tb_num);
+        gen_op_exit_tb();
+    } else {
+        /* jump to another page: currently not optimized */
+        gen_jmp_im(pc);
+        gen_movl_npc_im(npc);
+        gen_op_movl_T0_0();
+        gen_op_exit_tb();
+    }
+}
+
 static inline void gen_branch2(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2)
 {
     int l1;
@@ -569,18 +595,10 @@ static inline void gen_branch2(DisasContext *dc, long tb, target_ulong pc1, targ
 
     gen_op_jz_T2_label(l1);
 
-    gen_op_goto_tb0(TBPARAM(tb));
-    gen_jmp_im(pc1);
-    gen_movl_npc_im(pc1 + 4);
-    gen_op_movl_T0_im((long)tb + 0);
-    gen_op_exit_tb();
+    gen_goto_tb(dc, 0, pc1, pc1 + 4);
 
     gen_set_label(l1);
-    gen_op_goto_tb1(TBPARAM(tb));
-    gen_jmp_im(pc2);
-    gen_movl_npc_im(pc2 + 4);
-    gen_op_movl_T0_im((long)tb + 1);
-    gen_op_exit_tb();
+    gen_goto_tb(dc, 1, pc2, pc2 + 4);
 }
 
 static inline void gen_branch_a(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2)
@@ -591,27 +609,15 @@ static inline void gen_branch_a(DisasContext *dc, long tb, target_ulong pc1, tar
 
     gen_op_jz_T2_label(l1);
 
-    gen_op_goto_tb0(TBPARAM(tb));
-    gen_jmp_im(pc2);
-    gen_movl_npc_im(pc1);
-    gen_op_movl_T0_im((long)tb + 0);
-    gen_op_exit_tb();
+    gen_goto_tb(dc, 0, pc2, pc1);
 
     gen_set_label(l1);
-    gen_op_goto_tb1(TBPARAM(tb));
-    gen_jmp_im(pc2 + 4);
-    gen_movl_npc_im(pc2 + 8);
-    gen_op_movl_T0_im((long)tb + 1);
-    gen_op_exit_tb();
+    gen_goto_tb(dc, 1, pc2 + 4, pc2 + 8);
 }
 
 static inline void gen_branch(DisasContext *dc, long tb, target_ulong pc, target_ulong npc)
 {
-    gen_op_goto_tb0(TBPARAM(tb));
-    gen_jmp_im(pc);
-    gen_movl_npc_im(npc);
-    gen_op_movl_T0_im((long)tb + 0);
-    gen_op_exit_tb();
+    gen_goto_tb(dc, 0, pc, npc);
 }
 
 static inline void gen_generic_branch(DisasContext *dc, target_ulong npc1, target_ulong npc2)
@@ -1897,6 +1903,11 @@ static void disas_sparc_insn(DisasContext * dc)
 #else
                             gen_op_xor_T1_T0();
                             gen_op_wrpsr();
+                            save_state(dc);
+                            gen_op_next_insn();
+                           gen_op_movl_T0_0();
+                           gen_op_exit_tb();
+                           dc->is_br = 1;
 #endif
                         }
                         break;
@@ -2343,8 +2354,8 @@ static void disas_sparc_insn(DisasContext * dc)
                    gen_op_store_FT0_fpr(rd);
                    break;
                case 0x21:      /* load fsr */
+                   gen_op_ldst(ldf);
                    gen_op_ldfsr();
-                   gen_op_store_FT0_fpr(rd);
                    break;
                case 0x22:      /* load quad fpreg */
                    goto nfpu_insn;
@@ -2426,9 +2437,8 @@ static void disas_sparc_insn(DisasContext * dc)
                    gen_op_ldst(stf);
                    break;
                case 0x25: /* stfsr, V9 stxfsr */
-                    gen_op_load_fpr_FT0(rd);
-                   // XXX
                    gen_op_stfsr();
+                   gen_op_ldst(stf);
                    break;
                case 0x26: /* stdfq */
                    goto nfpu_insn;
@@ -2662,11 +2672,10 @@ CPUSPARCState *cpu_sparc_init(void)
 {
     CPUSPARCState *env;
 
-    cpu_exec_init();
-
-    if (!(env = malloc(sizeof(CPUSPARCState))))
-       return (NULL);
-    cpu_single_env = env;
+    env = qemu_mallocz(sizeof(CPUSPARCState));
+    if (!env)
+       return NULL;
+    cpu_exec_init(env);
     cpu_reset(env);
     return (env);
 }
index 78a215b..59a0b6d 100644 (file)
@@ -71,7 +71,7 @@ runcom: runcom.c
 
 # NOTE: -fomit-frame-pointer is currently needed : this is a bug in libqemu
 qruncom: qruncom.c ../i386-user/libqemu.a
-       $(CC) $(CFLAGS) -fomit-frame-pointer $(LDFLAGS) -I../target-i386 -I.. -I../i386-user \
+       $(CC) $(CFLAGS) -fomit-frame-pointer $(LDFLAGS) -I../target-i386 -I.. -I../i386-user -I../fpu \
               -o $@ $< -L../i386-user -lqemu -lm
 
 # arm test
@@ -83,7 +83,7 @@ hello-arm.o: hello-arm.c
 
 # XXX: find a way to compile easily a test for each arch
 test2:
-       @for arch in i386 arm sparc ppc; do \
+       @for arch in i386 arm armeb sparc ppc mips mipsel; do \
            ../$${arch}-user/qemu-$${arch} $${arch}/ls -l linux-test.c ; \
         done
 
index fcc069f..421e6a9 100644 (file)
 #include <fcntl.h>
 #include <sys/mman.h>
 #include <signal.h>
+#include <malloc.h>
 
 #include "cpu.h"
 
 //#define SIGTEST
 
-CPUState *cpu_single_env = NULL;
-
 void cpu_outb(CPUState *env, int addr, int val)
 {
     fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
@@ -88,6 +87,26 @@ void *qemu_malloc(size_t size)
     return malloc(size);
 }
 
+void *qemu_mallocz(size_t size)
+{
+    void *ptr;
+    ptr = qemu_malloc(size);
+    if (!ptr)
+        return NULL;
+    memset(ptr, 0, size);
+    return ptr;
+}
+
+void *qemu_vmalloc(size_t size)
+{
+    return memalign(4096, size);
+}
+
+void qemu_vfree(void *ptr)
+{
+    free(ptr);
+}
+
 void qemu_printf(const char *fmt, ...)
 {
     va_list ap;
@@ -206,20 +225,20 @@ int main(int argc, char **argv)
     seg = (COM_BASE_ADDR - 0x100) >> 4;
 
     cpu_x86_load_seg_cache(env, R_CS, seg, 
-                           (uint8_t *)(seg << 4), 0xffff, 0);
+                           (seg << 4), 0xffff, 0);
     cpu_x86_load_seg_cache(env, R_SS, seg, 
-                           (uint8_t *)(seg << 4), 0xffff, 0);
+                           (seg << 4), 0xffff, 0);
     cpu_x86_load_seg_cache(env, R_DS, seg, 
-                           (uint8_t *)(seg << 4), 0xffff, 0);
+                           (seg << 4), 0xffff, 0);
     cpu_x86_load_seg_cache(env, R_ES, seg, 
-                           (uint8_t *)(seg << 4), 0xffff, 0);
+                           (seg << 4), 0xffff, 0);
     cpu_x86_load_seg_cache(env, R_FS, seg, 
-                           (uint8_t *)(seg << 4), 0xffff, 0);
+                           (seg << 4), 0xffff, 0);
     cpu_x86_load_seg_cache(env, R_GS, seg, 
-                           (uint8_t *)(seg << 4), 0xffff, 0);
+                           (seg << 4), 0xffff, 0);
 
     /* exception support */
-    env->idt.base = (void *)idt_table;
+    env->idt.base = (unsigned long)idt_table;
     env->idt.limit = sizeof(idt_table) - 1;
     set_idt(0, 0);
     set_idt(1, 0);
@@ -265,7 +284,7 @@ int main(int argc, char **argv)
         case EXCP0D_GPF:
             {
                 int int_num, ah;
-                int_num = *(env->segs[R_CS].base + env->eip + 1);
+                int_num = *(uint8_t *)(env->segs[R_CS].base + env->eip + 1);
                 if (int_num != 0x21)
                     goto unknown_int;
                 ah = (env->regs[R_EAX] >> 8) & 0xff;
@@ -293,7 +312,7 @@ int main(int argc, char **argv)
                 default:
                 unknown_int:
                     fprintf(stderr, "unsupported int 0x%02x\n", int_num);
-                    cpu_dump_state(env, stderr, 0);
+                    cpu_dump_state(env, stderr, fprintf, 0);
                     //                    exit(1);
                 }
                 env->eip += 2;
@@ -301,7 +320,7 @@ int main(int argc, char **argv)
             break;
         default:
             fprintf(stderr, "unhandled cpu_exec return code (0x%x)\n", ret);
-            cpu_dump_state(env, stderr, 0);
+            cpu_dump_state(env, stderr, fprintf, 0);
             exit(1);
         }
     }
index cac91c5..0de429f 100644 (file)
@@ -53,6 +53,8 @@ uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
 #elif defined(TARGET_SPARC)
 target_ulong gen_opc_npc[OPC_BUF_SIZE];
 target_ulong gen_opc_jump_pc[2];
+#elif defined(TARGET_MIPS)
+uint32_t gen_opc_hflags[OPC_BUF_SIZE];
 #endif
 
 int code_copy_enabled = 1;
@@ -302,6 +304,8 @@ int cpu_restore_state(TranslationBlock *tb,
     }
 #elif defined(TARGET_MIPS)
     env->PC = gen_opc_pc[j];
+    env->hflags &= ~MIPS_HFLAG_BMASK;
+    env->hflags |= gen_opc_hflags[j];
 #endif
     return 0;
 }
diff --git a/qemu/usb-linux.c b/qemu/usb-linux.c
new file mode 100644 (file)
index 0000000..216ac20
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * 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
+ * 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"
+
+#if defined(__linux__)
+#include <dirent.h>
+#include <sys/ioctl.h>
+#include <linux/usbdevice_fs.h>
+#include <linux/version.h>
+
+/* We redefine it to avoid version problems */
+struct usb_ctrltransfer {
+    uint8_t  bRequestType;
+    uint8_t  bRequest;
+    uint16_t wValue;
+    uint16_t wIndex;
+    uint16_t wLength;
+    uint32_t timeout;
+    void *data;
+};
+
+typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
+                        int vendor_id, int product_id, 
+                        const char *product_name, int speed);
+static int usb_host_find_device(int *pbus_num, int *paddr, 
+                                const char *devname);
+
+//#define DEBUG
+
+#define USBDEVFS_PATH "/proc/bus/usb"
+
+typedef struct USBHostDevice {
+    USBDevice dev;
+    int fd;
+} USBHostDevice;
+
+static void usb_host_handle_reset(USBDevice *dev)
+{
+#if 0
+    USBHostDevice *s = (USBHostDevice *)dev;
+    /* USBDEVFS_RESET, but not the first time as it has already be
+       done by the host OS */
+    ioctl(s->fd, USBDEVFS_RESET);
+#endif
+} 
+
+static int usb_host_handle_control(USBDevice *dev,
+                                   int request,
+                                   int value,
+                                   int index,
+                                   int length,
+                                   uint8_t *data)
+{
+    USBHostDevice *s = (USBHostDevice *)dev;
+    struct usb_ctrltransfer ct;
+    int ret;
+
+    if (request == (DeviceOutRequest | USB_REQ_SET_ADDRESS)) {
+        /* specific SET_ADDRESS support */
+        dev->addr = value;
+        return 0;
+    } else {
+        ct.bRequestType = request >> 8;
+        ct.bRequest = request;
+        ct.wValue = value;
+        ct.wIndex = index;
+        ct.wLength = length;
+        ct.timeout = 50;
+        ct.data = data;
+        ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
+        if (ret < 0) {
+            switch(errno) {
+            case ETIMEDOUT:
+                return USB_RET_NAK;
+            default:
+                return USB_RET_STALL;
+            }
+        } else {
+            return ret;
+        }
+   }
+}
+
+static int usb_host_handle_data(USBDevice *dev, int pid, 
+                                uint8_t devep,
+                                uint8_t *data, int len)
+{
+    USBHostDevice *s = (USBHostDevice *)dev;
+    struct usbdevfs_bulktransfer bt;
+    int ret;
+
+    /* XXX: optimize and handle all data types by looking at the
+       config descriptor */
+    if (pid == USB_TOKEN_IN)
+        devep |= 0x80;
+    bt.ep = devep;
+    bt.len = len;
+    bt.timeout = 50;
+    bt.data = data;
+    ret = ioctl(s->fd, USBDEVFS_BULK, &bt);
+    if (ret < 0) {
+        switch(errno) {
+        case ETIMEDOUT:
+            return USB_RET_NAK;
+        case EPIPE:
+        default:
+#ifdef DEBUG
+            printf("handle_data: errno=%d\n", errno);
+#endif
+            return USB_RET_STALL;
+        }
+    } else {
+        return ret;
+    }
+}
+
+/* XXX: exclude high speed devices or implement EHCI */
+USBDevice *usb_host_device_open(const char *devname)
+{
+    int fd, interface, ret, i;
+    USBHostDevice *dev;
+    struct usbdevfs_connectinfo ci;
+    uint8_t descr[1024];
+    char buf[1024];
+    int descr_len, dev_descr_len, config_descr_len, nb_interfaces;
+    int bus_num, addr;
+
+    if (usb_host_find_device(&bus_num, &addr, devname) < 0) 
+        return NULL;
+    
+    snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", 
+             bus_num, addr);
+    fd = open(buf, O_RDWR);
+    if (fd < 0) {
+        perror(buf);
+        return NULL;
+    }
+
+    /* read the config description */
+    descr_len = read(fd, descr, sizeof(descr));
+    if (descr_len <= 0) {
+        perror("read descr");
+        goto fail;
+    }
+    
+    i = 0;
+    dev_descr_len = descr[0];
+    if (dev_descr_len > descr_len)
+        goto fail;
+    i += dev_descr_len;
+    config_descr_len = descr[i];
+    if (i + config_descr_len > descr_len)
+        goto fail;
+    nb_interfaces = descr[i + 4];
+    if (nb_interfaces != 1) {
+        /* NOTE: currently we grab only one interface */
+        fprintf(stderr, "usb_host: only one interface supported\n");
+        goto fail;
+    }
+
+#ifdef USBDEVFS_DISCONNECT
+    /* earlier Linux 2.4 do not support that */
+    {
+        struct usbdevfs_ioctl ctrl;
+        ctrl.ioctl_code = USBDEVFS_DISCONNECT;
+        ctrl.ifno = 0;
+        ret = ioctl(fd, USBDEVFS_IOCTL, &ctrl);
+        if (ret < 0 && errno != ENODATA) {
+            perror("USBDEVFS_DISCONNECT");
+            goto fail;
+        }
+    }
+#endif
+
+    /* XXX: only grab if all interfaces are free */
+    interface = 0;
+    ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface);
+    if (ret < 0) {
+        if (errno == EBUSY) {
+            fprintf(stderr, "usb_host: device already grabbed\n");
+        } else {
+            perror("USBDEVFS_CLAIMINTERFACE");
+        }
+    fail:
+        close(fd);
+        return NULL;
+    }
+
+    ret = ioctl(fd, USBDEVFS_CONNECTINFO, &ci);
+    if (ret < 0) {
+        perror("USBDEVFS_CONNECTINFO");
+        goto fail;
+    }
+
+#ifdef DEBUG
+    printf("host USB device %d.%d grabbed\n", bus_num, addr);
+#endif    
+
+    dev = qemu_mallocz(sizeof(USBHostDevice));
+    if (!dev)
+        goto fail;
+    dev->fd = fd;
+    if (ci.slow)
+        dev->dev.speed = USB_SPEED_LOW;
+    else
+        dev->dev.speed = USB_SPEED_HIGH;
+    dev->dev.handle_packet = usb_generic_handle_packet;
+
+    dev->dev.handle_reset = usb_host_handle_reset;
+    dev->dev.handle_control = usb_host_handle_control;
+    dev->dev.handle_data = usb_host_handle_data;
+    return (USBDevice *)dev;
+}
+
+static int get_tag_value(char *buf, int buf_size,
+                         const char *str, const char *tag, 
+                         const char *stopchars)
+{
+    const char *p;
+    char *q;
+    p = strstr(str, tag);
+    if (!p)
+        return -1;
+    p += strlen(tag);
+    while (isspace(*p))
+        p++;
+    q = buf;
+    while (*p != '\0' && !strchr(stopchars, *p)) {
+        if ((q - buf) < (buf_size - 1))
+            *q++ = *p;
+        p++;
+    }
+    *q = '\0';
+    return q - buf;
+}
+
+static int usb_host_scan(void *opaque, USBScanFunc *func)
+{
+    FILE *f;
+    char line[1024];
+    char buf[1024];
+    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");
+        return 0;
+    }
+    device_count = 0;
+    bus_num = addr = speed = class_id = product_id = vendor_id = 0;
+    ret = 0;
+    for(;;) {
+        if (fgets(line, sizeof(line), f) == NULL)
+            break;
+        if (strlen(line) > 0)
+            line[strlen(line) - 1] = '\0';
+        if (line[0] == 'T' && line[1] == ':') {
+            if (device_count) {
+                ret = func(opaque, bus_num, addr, class_id, vendor_id, 
+                           product_id, product_name, speed);
+                if (ret)
+                    goto the_end;
+            }
+            if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0)
+                goto fail;
+            bus_num = atoi(buf);
+            if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0)
+                goto fail;
+            addr = atoi(buf);
+            if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0)
+                goto fail;
+            if (!strcmp(buf, "480"))
+                speed = USB_SPEED_HIGH;
+            else if (!strcmp(buf, "1.5"))
+                speed = USB_SPEED_LOW;
+            else
+                speed = USB_SPEED_FULL;
+            product_name[0] = '\0';
+            class_id = 0xff;
+            device_count++;
+            product_id = 0;
+            vendor_id = 0;
+        } else if (line[0] == 'P' && line[1] == ':') {
+            if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0)
+                goto fail;
+            vendor_id = strtoul(buf, NULL, 16);
+            if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0)
+                goto fail;
+            product_id = strtoul(buf, NULL, 16);
+        } else if (line[0] == 'S' && line[1] == ':') {
+            if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0)
+                goto fail;
+            pstrcpy(product_name, sizeof(product_name), buf);
+        } else if (line[0] == 'D' && line[1] == ':') {
+            if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0)
+                goto fail;
+            class_id = strtoul(buf, NULL, 16);
+        }
+    fail: ;
+    }
+    if (device_count) {
+        ret = func(opaque, bus_num, addr, class_id, vendor_id, 
+                   product_id, product_name, speed);
+    }
+ the_end:
+    fclose(f);
+    return ret;
+}
+
+typedef struct FindDeviceState {
+    int vendor_id;
+    int product_id;
+    int bus_num;
+    int addr;
+} FindDeviceState;
+
+static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, 
+                                     int class_id,
+                                     int vendor_id, int product_id, 
+                                     const char *product_name, int speed)
+{
+    FindDeviceState *s = opaque;
+    if (vendor_id == s->vendor_id &&
+        product_id == s->product_id) {
+        s->bus_num = bus_num;
+        s->addr = addr;
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+/* 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, 
+                                const char *devname)
+{
+    const char *p;
+    int ret;
+    FindDeviceState fs;
+
+    p = strchr(devname, '.');
+    if (p) {
+        *pbus_num = strtoul(devname, NULL, 0);
+        *paddr = strtoul(p + 1, NULL, 0);
+        return 0;
+    }
+    p = strchr(devname, ':');
+    if (p) {
+        fs.vendor_id = strtoul(devname, NULL, 16);
+        fs.product_id = strtoul(p + 1, NULL, 16);
+        ret = usb_host_scan(&fs, usb_host_find_device_scan);
+        if (ret) {
+            *pbus_num = fs.bus_num;
+            *paddr = fs.addr;
+            return 0;
+        }
+    }
+    return -1;
+}
+
+/**********************/
+/* USB host device info */
+
+struct usb_class_info {
+    int class;
+    const char *class_name;
+};
+
+static const struct usb_class_info usb_class_info[] = {
+    { USB_CLASS_AUDIO, "Audio"},
+    { USB_CLASS_COMM, "Communication"},
+    { USB_CLASS_HID, "HID"},
+    { USB_CLASS_HUB, "Hub" },
+    { USB_CLASS_PHYSICAL, "Physical" },
+    { USB_CLASS_PRINTER, "Printer" },
+    { USB_CLASS_MASS_STORAGE, "Storage" },
+    { USB_CLASS_CDC_DATA, "Data" },
+    { USB_CLASS_APP_SPEC, "Application Specific" },
+    { USB_CLASS_VENDOR_SPEC, "Vendor Specific" },
+    { USB_CLASS_STILL_IMAGE, "Still Image" },
+    { USB_CLASS_CSCID,         "Smart Card" },
+    { USB_CLASS_CONTENT_SEC, "Content Security" },
+    { -1, NULL }
+};
+
+static const char *usb_class_str(uint8_t class)
+{
+    const struct usb_class_info *p;
+    for(p = usb_class_info; p->class != -1; p++) {
+        if (p->class == class)
+            break;
+    }
+    return p->class_name;
+}
+
+void usb_info_device(int bus_num, int addr, int class_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"; 
+        break;
+    case USB_SPEED_FULL: 
+        speed_str = "12"; 
+        break;
+    case USB_SPEED_HIGH: 
+        speed_str = "480"; 
+        break;
+    default:
+        speed_str = "?"; 
+        break;
+    }
+
+    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) 
+        term_printf("    %s:", class_str);
+    else
+        term_printf("    Class %02x:", class_id);
+    term_printf(" USB device %04x:%04x", vendor_id, product_id);
+    if (product_name[0] != '\0')
+        term_printf(", %s", product_name);
+    term_printf("\n");
+}
+
+static int usb_host_info_device(void *opaque, int bus_num, int addr, 
+                                int class_id,
+                                int vendor_id, int product_id, 
+                                const char *product_name,
+                                int speed)
+{
+    usb_info_device(bus_num, addr, class_id, vendor_id, product_id,
+                    product_name, speed);
+    return 0;
+}
+
+void usb_host_info(void)
+{
+    usb_host_scan(NULL, usb_host_info_device);
+}
+
+#else
+
+void usb_host_info(void)
+{
+    term_printf("USB host devices not supported\n");
+}
+
+/* XXX: modify configure to compile the right host driver */
+USBDevice *usb_host_device_open(const char *devname)
+{
+    return NULL;
+}
+
+#endif
index e7cd966..70da053 100644 (file)
--- a/qemu/vl.c
+++ b/qemu/vl.c
@@ -40,6 +40,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <dirent.h>
+#include <netdb.h>
 #ifdef _BSD
 #include <sys/stat.h>
 #ifndef __APPLE__
@@ -51,6 +52,7 @@
 #include <pty.h>
 #include <malloc.h>
 #include <linux/rtc.h>
+#include <linux/ppdev.h>
 #endif
 #endif
 
@@ -81,8 +83,6 @@
 
 #include "exec-all.h"
 
-//#define DO_TB_FLUSH
-
 #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
 
 //#define DEBUG_UNUSED_IOPORT
 
 const char *bios_dir = CONFIG_QEMU_SHAREDIR;
 char phys_ram_file[1024];
-CPUState *global_env;
-CPUState *cpu_single_env;
 void *ioport_opaque[MAX_IOPORTS];
 IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
 IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
@@ -121,18 +119,11 @@ const char* keyboard_layout = NULL;
 int64_t ticks_per_sec;
 int boot_device = 'c';
 int ram_size;
-static char network_script[1024];
 int pit_min_timer_count = 0;
 int nb_nics;
-NetDriverState nd_table[MAX_NICS];
+NICInfo nd_table[MAX_NICS];
 QEMUTimer *gui_timer;
 int vm_running;
-int audio_enabled = 0;
-int sb16_enabled = 1;
-int adlib_enabled = 1;
-int gus_enabled = 1;
-int pci_enabled = 1;
-int prep_enabled = 0;
 int rtc_utc = 1;
 int cirrus_vga_enabled = 1;
 #ifdef TARGET_SPARC
@@ -150,6 +141,18 @@ CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
 #ifdef TARGET_I386
 int win2k_install_hack = 0;
 #endif
+int usb_enabled = 0;
+USBPort *vm_usb_ports[MAX_VM_USB_PORTS];
+USBDevice *vm_usb_hub;
+static VLANState *first_vlan;
+int smp_cpus = 1;
+#if defined(TARGET_SPARC)
+#define MAX_CPUS 16
+#elif defined(TARGET_I386)
+#define MAX_CPUS 255
+#else
+#define MAX_CPUS 1
+#endif
 
 /***********************************************************/
 /* x86 ISA bus support */
@@ -421,16 +424,20 @@ int cpu_inl(CPUState *env, int addr)
 void hw_error(const char *fmt, ...)
 {
     va_list ap;
+    CPUState *env;
 
     va_start(ap, fmt);
     fprintf(stderr, "qemu: hardware error: ");
     vfprintf(stderr, fmt, ap);
     fprintf(stderr, "\n");
+    for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        fprintf(stderr, "CPU #%d:\n", env->cpu_index);
 #ifdef TARGET_I386
-    cpu_dump_state(global_env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
+        cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU);
 #else
-    cpu_dump_state(global_env, stderr, fprintf, 0);
+        cpu_dump_state(env, stderr, fprintf, 0);
 #endif
+    }
     va_end(ap);
     abort();
 }
@@ -873,13 +880,16 @@ static void host_alarm_handler(int host_signum)
                            qemu_get_clock(vm_clock)) ||
         qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
                            qemu_get_clock(rt_clock))) {
-        /* stop the cpu because a timer occured */
-        cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
+        CPUState *env = cpu_single_env;
+        if (env) {
+            /* stop the currently executing cpu because a timer occured */
+            cpu_interrupt(env, CPU_INTERRUPT_EXIT);
 #ifdef USE_KQEMU
-        if (global_env->kqemu_enabled) {
-            kqemu_cpu_interrupt(global_env);
-        }
+            if (env->kqemu_enabled) {
+                kqemu_cpu_interrupt(env);
+            }
 #endif
+        }
     }
 }
 
@@ -930,7 +940,7 @@ static void init_timers(void)
 #ifdef _WIN32
     {
         int count=0;
-        timerID = timeSetEvent(10,    // interval (ms)
+        timerID = timeSetEvent(1,     // interval (ms)
                                0,     // resolution
                                host_alarm_handler, // function
                                (DWORD)&count,  // user parameter
@@ -1009,6 +1019,13 @@ int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
     return s->chr_write(s, buf, len);
 }
 
+int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg)
+{
+    if (!s->chr_ioctl)
+        return -ENOTSUP;
+    return s->chr_ioctl(s, cmd, arg);
+}
+
 void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
 {
     char buf[4096];
@@ -1064,10 +1081,10 @@ CharDriverState *qemu_chr_open_null(void)
 
 typedef struct {
     int fd_in, fd_out;
-    /* for nographic stdio only */
     IOCanRWHandler *fd_can_read; 
     IOReadHandler *fd_read;
     void *fd_opaque;
+    int max_size;
 } FDCharDriver;
 
 #define STDIO_MAX_CLIENTS 2
@@ -1101,18 +1118,48 @@ static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
     return unix_write(s->fd_out, buf, len);
 }
 
+static int fd_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    FDCharDriver *s = chr->opaque;
+
+    s->max_size = s->fd_can_read(s->fd_opaque);
+    return s->max_size;
+}
+
+static void fd_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    FDCharDriver *s = chr->opaque;
+    int size, len;
+    uint8_t buf[1024];
+    
+    len = sizeof(buf);
+    if (len > s->max_size)
+        len = s->max_size;
+    if (len == 0)
+        return;
+    size = read(s->fd_in, buf, len);
+    if (size > 0) {
+        s->fd_read(s->fd_opaque, buf, size);
+    }
+}
+
 static void fd_chr_add_read_handler(CharDriverState *chr, 
                                     IOCanRWHandler *fd_can_read, 
                                     IOReadHandler *fd_read, void *opaque)
 {
     FDCharDriver *s = chr->opaque;
 
-    if (nographic && s->fd_in == 0) {
+    if (s->fd_in >= 0) {
         s->fd_can_read = fd_can_read;
         s->fd_read = fd_read;
         s->fd_opaque = opaque;
-    } else {
-        qemu_add_fd_read_handler(s->fd_in, fd_can_read, fd_read, opaque);
+        if (nographic && s->fd_in == 0) {
+        } else {
+            qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll, 
+                                 fd_chr_read, NULL, chr);
+        }
     }
 }
 
@@ -1138,6 +1185,27 @@ CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
     return chr;
 }
 
+CharDriverState *qemu_chr_open_file_out(const char *file_out)
+{
+    int fd_out;
+
+    fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY);
+    if (fd_out < 0)
+        return NULL;
+    return qemu_chr_open_fd(-1, fd_out);
+}
+
+CharDriverState *qemu_chr_open_pipe(const char *filename)
+{
+    int fd;
+
+    fd = open(filename, O_RDWR | O_BINARY);
+    if (fd < 0)
+        return NULL;
+    return qemu_chr_open_fd(fd, fd);
+}
+
+
 /* for STDIO, we handle the case where several clients use it
    (nographic mode) */
 
@@ -1226,7 +1294,7 @@ static void stdio_received_byte(int ch)
     }
 }
 
-static int stdio_can_read(void *opaque)
+static int stdio_read_poll(void *opaque)
 {
     CharDriverState *chr;
     FDCharDriver *s;
@@ -1249,11 +1317,14 @@ static int stdio_can_read(void *opaque)
     }
 }
 
-static void stdio_read(void *opaque, const uint8_t *buf, int size)
+static void stdio_read(void *opaque)
 {
-    int i;
-    for(i = 0; i < size; i++)
-        stdio_received_byte(buf[i]);
+    int size;
+    uint8_t buf[1];
+    
+    size = read(0, buf, 1);
+    if (size > 0)
+        stdio_received_byte(buf[0]);
 }
 
 /* init terminal so that we can grab keys */
@@ -1302,7 +1373,7 @@ CharDriverState *qemu_chr_open_stdio(void)
             return NULL;
         chr = qemu_chr_open_fd(0, 1);
         if (stdio_nb_clients == 0)
-            qemu_add_fd_read_handler(0, stdio_can_read, stdio_read, NULL);
+            qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL);
         client_index = stdio_nb_clients;
     } else {
         if (stdio_nb_clients != 0)
@@ -1320,6 +1391,7 @@ CharDriverState *qemu_chr_open_stdio(void)
 #if defined(__linux__)
 CharDriverState *qemu_chr_open_pty(void)
 {
+    struct termios tty;
     char slave_name[1024];
     int master_fd, slave_fd;
     
@@ -1327,9 +1399,213 @@ CharDriverState *qemu_chr_open_pty(void)
     if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) {
         return NULL;
     }
+    
+    /* Disabling local echo and line-buffered output */
+    tcgetattr (master_fd, &tty);
+    tty.c_lflag &= ~(ECHO|ICANON|ISIG);
+    tty.c_cc[VMIN] = 1;
+    tty.c_cc[VTIME] = 0;
+    tcsetattr (master_fd, TCSAFLUSH, &tty);
+
     fprintf(stderr, "char device redirected to %s\n", slave_name);
     return qemu_chr_open_fd(master_fd, master_fd);
 }
+
+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", 
+           speed, parity, data_bits, stop_bits);
+#endif
+    tcgetattr (fd, &tty);
+
+    switch(speed) {
+    case 50:
+        spd = B50;
+        break;
+    case 75:
+        spd = B75;
+        break;
+    case 300:
+        spd = B300;
+        break;
+    case 600:
+        spd = B600;
+        break;
+    case 1200:
+        spd = B1200;
+        break;
+    case 2400:
+        spd = B2400;
+        break;
+    case 4800:
+        spd = B4800;
+        break;
+    case 9600:
+        spd = B9600;
+        break;
+    case 19200:
+        spd = B19200;
+        break;
+    case 38400:
+        spd = B38400;
+        break;
+    case 57600:
+        spd = B57600;
+        break;
+    default:
+    case 115200:
+        spd = B115200;
+        break;
+    }
+
+    cfsetispeed(&tty, spd);
+    cfsetospeed(&tty, spd);
+
+    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
+                          |INLCR|IGNCR|ICRNL|IXON);
+    tty.c_oflag |= OPOST;
+    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
+    tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS);
+    switch(data_bits) {
+    default:
+    case 8:
+        tty.c_cflag |= CS8;
+        break;
+    case 7:
+        tty.c_cflag |= CS7;
+        break;
+    case 6:
+        tty.c_cflag |= CS6;
+        break;
+    case 5:
+        tty.c_cflag |= CS5;
+        break;
+    }
+    switch(parity) {
+    default:
+    case 'N':
+        break;
+    case 'E':
+        tty.c_cflag |= PARENB;
+        break;
+    case 'O':
+        tty.c_cflag |= PARENB | PARODD;
+        break;
+    }
+    
+    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, 
+                            ssp->data_bits, ssp->stop_bits);
+        }
+        break;
+    case CHR_IOCTL_SERIAL_SET_BREAK:
+        {
+            int enable = *(int *)arg;
+            if (enable)
+                tcsendbreak(s->fd_in, 1);
+        }
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+CharDriverState *qemu_chr_open_tty(const char *filename)
+{
+    CharDriverState *chr;
+    int fd;
+
+    fd = open(filename, O_RDWR | O_NONBLOCK);
+    if (fd < 0)
+        return NULL;
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+    tty_serial_init(fd, 115200, 'N', 8, 1);
+    chr = qemu_chr_open_fd(fd, fd);
+    if (!chr)
+        return NULL;
+    chr->chr_ioctl = tty_serial_ioctl;
+    return chr;
+}
+
+static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
+{
+    int fd = (int)chr->opaque;
+    uint8_t b;
+
+    switch(cmd) {
+    case CHR_IOCTL_PP_READ_DATA:
+        if (ioctl(fd, PPRDATA, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_DATA:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPWDATA, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_CONTROL:
+        if (ioctl(fd, PPRCONTROL, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_CONTROL:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPWCONTROL, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_STATUS:
+        if (ioctl(fd, PPRSTATUS, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+CharDriverState *qemu_chr_open_pp(const char *filename)
+{
+    CharDriverState *chr;
+    int fd;
+
+    fd = open(filename, O_RDWR);
+    if (fd < 0)
+        return NULL;
+
+    if (ioctl(fd, PPCLAIM) < 0) {
+        close(fd);
+        return NULL;
+    }
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    if (!chr) {
+        close(fd);
+        return NULL;
+    }
+    chr->opaque = (void *)fd;
+    chr->chr_write = null_chr_write;
+    chr->chr_add_read_handler = null_chr_add_read_handler;
+    chr->chr_ioctl = pp_ioctl;
+    return chr;
+}
+
 #else
 CharDriverState *qemu_chr_open_pty(void)
 {
@@ -1341,25 +1617,38 @@ CharDriverState *qemu_chr_open_pty(void)
 
 CharDriverState *qemu_chr_open(const char *filename)
 {
+    const char *p;
     if (!strcmp(filename, "vc")) {
         return text_console_init(&display_state);
     } else if (!strcmp(filename, "null")) {
         return qemu_chr_open_null();
     } else 
 #ifndef _WIN32
-    if (!strcmp(filename, "pty")) {
+    if (strstart(filename, "file:", &p)) {
+        return qemu_chr_open_file_out(p);
+    } else if (strstart(filename, "pipe:", &p)) {
+        return qemu_chr_open_pipe(p);
+    } else if (!strcmp(filename, "pty")) {
         return qemu_chr_open_pty();
     } else if (!strcmp(filename, "stdio")) {
         return qemu_chr_open_stdio();
     } else 
 #endif
+#if defined(__linux__)
+    if (strstart(filename, "/dev/parport", NULL)) {
+        return qemu_chr_open_pp(filename);
+    } else 
+    if (strstart(filename, "/dev/", NULL)) {
+        return qemu_chr_open_tty(filename);
+    } else 
+#endif
     {
         return NULL;
     }
 }
 
 /***********************************************************/
-/* Linux network device redirectors */
+/* network device redirectors */
 
 void hex_dump(FILE *f, const uint8_t *buf, int size)
 {
@@ -1387,107 +1676,171 @@ void hex_dump(FILE *f, const uint8_t *buf, int size)
     }
 }
 
-void qemu_send_packet(NetDriverState *nd, const uint8_t *buf, int size)
+static int parse_macaddr(uint8_t *macaddr, const char *p)
 {
-    nd->send_packet(nd, buf, size);
+    int i;
+    for(i = 0; i < 6; i++) {
+        macaddr[i] = strtol(p, (char **)&p, 16);
+        if (i == 5) {
+            if (*p != '\0') 
+                return -1;
+        } else {
+            if (*p != ':') 
+                return -1;
+            p++;
+        }
+    }
+    return 0;
 }
 
-void qemu_add_read_packet(NetDriverState *nd, IOCanRWHandler *fd_can_read, 
-                          IOReadHandler *fd_read, void *opaque)
+static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
 {
-    nd->add_read_packet(nd, fd_can_read, fd_read, opaque);
+    const char *p, *p1;
+    int len;
+    p = *pp;
+    p1 = strchr(p, sep);
+    if (!p1)
+        return -1;
+    len = p1 - p;
+    p1++;
+    if (buf_size > 0) {
+        if (len > buf_size - 1)
+            len = buf_size - 1;
+        memcpy(buf, p, len);
+        buf[len] = '\0';
+    }
+    *pp = p1;
+    return 0;
 }
 
-/* dummy network adapter */
+int parse_host_port(struct sockaddr_in *saddr, const char *str)
+{
+    char buf[512];
+    struct hostent *he;
+    const char *p, *r;
+    int port;
 
-static void dummy_send_packet(NetDriverState *nd, const uint8_t *buf, int size)
+    p = str;
+    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
+        return -1;
+    saddr->sin_family = AF_INET;
+    if (buf[0] == '\0') {
+        saddr->sin_addr.s_addr = 0;
+    } else {
+        if (isdigit(buf[0])) {
+            if (!inet_aton(buf, &saddr->sin_addr))
+                return -1;
+        } else {
+#ifdef _WIN32
+            return -1;
+#else
+            if ((he = gethostbyname(buf)) == NULL)
+                return - 1;
+            saddr->sin_addr = *(struct in_addr *)he->h_addr;
+#endif
+        }
+    }
+    port = strtol(p, (char **)&r, 0);
+    if (r == p)
+        return -1;
+    saddr->sin_port = htons(port);
+    return 0;
+}
+
+/* find or alloc a new VLAN */
+VLANState *qemu_find_vlan(int id)
 {
+    VLANState **pvlan, *vlan;
+    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+        if (vlan->id == id)
+            return vlan;
+    }
+    vlan = qemu_mallocz(sizeof(VLANState));
+    if (!vlan)
+        return NULL;
+    vlan->id = id;
+    vlan->next = NULL;
+    pvlan = &first_vlan;
+    while (*pvlan != NULL)
+        pvlan = &(*pvlan)->next;
+    *pvlan = vlan;
+    return vlan;
 }
 
-static void dummy_add_read_packet(NetDriverState *nd, 
-                                  IOCanRWHandler *fd_can_read, 
-                                  IOReadHandler *fd_read, void *opaque)
+VLANClientState *qemu_new_vlan_client(VLANState *vlan,
+                                      IOReadHandler *fd_read, void *opaque)
 {
+    VLANClientState *vc, **pvc;
+    vc = qemu_mallocz(sizeof(VLANClientState));
+    if (!vc)
+        return NULL;
+    vc->fd_read = fd_read;
+    vc->opaque = opaque;
+    vc->vlan = vlan;
+
+    vc->next = NULL;
+    pvc = &vlan->first_client;
+    while (*pvc != NULL)
+        pvc = &(*pvc)->next;
+    *pvc = vc;
+    return vc;
 }
 
-static int net_dummy_init(NetDriverState *nd)
+void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size)
 {
-    nd->send_packet = dummy_send_packet;
-    nd->add_read_packet = dummy_add_read_packet;
-    pstrcpy(nd->ifname, sizeof(nd->ifname), "dummy");
-    return 0;
+    VLANState *vlan = vc1->vlan;
+    VLANClientState *vc;
+
+#if 0
+    printf("vlan %d send:\n", vlan->id);
+    hex_dump(stdout, buf, size);
+#endif
+    for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
+        if (vc != vc1) {
+            vc->fd_read(vc->opaque, buf, size);
+        }
+    }
 }
 
 #if defined(CONFIG_SLIRP)
 
 /* slirp network adapter */
 
-static void *slirp_fd_opaque;
-static IOCanRWHandler *slirp_fd_can_read;
-static IOReadHandler *slirp_fd_read;
 static int slirp_inited;
+static VLANClientState *slirp_vc;
 
 int slirp_can_output(void)
 {
-    return slirp_fd_can_read(slirp_fd_opaque);
+    return 1;
 }
 
 void slirp_output(const uint8_t *pkt, int pkt_len)
 {
 #if 0
-    printf("output:\n");
+    printf("slirp output:\n");
     hex_dump(stdout, pkt, pkt_len);
 #endif
-    slirp_fd_read(slirp_fd_opaque, pkt, pkt_len);
+    qemu_send_packet(slirp_vc, pkt, pkt_len);
 }
 
-static void slirp_send_packet(NetDriverState *nd, const uint8_t *buf, int size)
+static void slirp_receive(void *opaque, const uint8_t *buf, int size)
 {
 #if 0
-    printf("input:\n");
+    printf("slirp input:\n");
     hex_dump(stdout, buf, size);
 #endif
     slirp_input(buf, size);
 }
 
-static void slirp_add_read_packet(NetDriverState *nd, 
-                                  IOCanRWHandler *fd_can_read, 
-                                  IOReadHandler *fd_read, void *opaque)
-{
-    slirp_fd_opaque = opaque;
-    slirp_fd_can_read = fd_can_read;
-    slirp_fd_read = fd_read;
-}
-
-static int net_slirp_init(NetDriverState *nd)
+static int net_slirp_init(VLANState *vlan)
 {
     if (!slirp_inited) {
         slirp_inited = 1;
         slirp_init();
     }
-    nd->send_packet = slirp_send_packet;
-    nd->add_read_packet = slirp_add_read_packet;
-    pstrcpy(nd->ifname, sizeof(nd->ifname), "slirp");
-    return 0;
-}
-
-static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
-{
-    const char *p, *p1;
-    int len;
-    p = *pp;
-    p1 = strchr(p, sep);
-    if (!p1)
-        return -1;
-    len = p1 - p;
-    p1++;
-    if (buf_size > 0) {
-        if (len > buf_size - 1)
-            len = buf_size - 1;
-        memcpy(buf, p, len);
-        buf[len] = '\0';
-    }
-    *pp = p1;
+    slirp_vc = qemu_new_vlan_client(vlan, 
+                                    slirp_receive, NULL);
+    snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector");
     return 0;
 }
 
@@ -1622,117 +1975,833 @@ void net_slirp_smb(const char *exported_dir)
     snprintf(smb_cmdline, sizeof(smb_cmdline), "/usr/sbin/smbd -s %s",
              smb_conf);
     
-    slirp_add_exec(0, smb_cmdline, 4, 139);
+    slirp_add_exec(0, smb_cmdline, 4, 139);
+}
+
+#endif /* !defined(_WIN32) */
+
+#endif /* CONFIG_SLIRP */
+
+#if !defined(_WIN32)
+
+typedef struct TAPState {
+    VLANClientState *vc;
+    int fd;
+} TAPState;
+
+static void tap_receive(void *opaque, const uint8_t *buf, int size)
+{
+    TAPState *s = opaque;
+    int ret;
+    for(;;) {
+        ret = write(s->fd, buf, size);
+        if (ret < 0 && (errno == EINTR || errno == EAGAIN)) {
+        } else {
+            break;
+        }
+    }
+}
+
+static void tap_send(void *opaque)
+{
+    TAPState *s = opaque;
+    uint8_t buf[4096];
+    int size;
+
+    size = read(s->fd, buf, sizeof(buf));
+    if (size > 0) {
+        qemu_send_packet(s->vc, buf, size);
+    }
+}
+
+/* fd support */
+
+static TAPState *net_tap_fd_init(VLANState *vlan, int fd)
+{
+    TAPState *s;
+
+    s = qemu_mallocz(sizeof(TAPState));
+    if (!s)
+        return NULL;
+    s->fd = fd;
+    s->vc = qemu_new_vlan_client(vlan, tap_receive, s);
+    qemu_set_fd_handler(s->fd, tap_send, NULL, s);
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: fd=%d", fd);
+    return s;
+}
+
+#ifdef _BSD
+static int tap_open(char *ifname, int ifname_size)
+{
+    int fd;
+    char *dev;
+    struct stat s;
+
+    fd = open("/dev/tap", O_RDWR);
+    if (fd < 0) {
+        fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n");
+        return -1;
+    }
+
+    fstat(fd, &s);
+    dev = devname(s.st_rdev, S_IFCHR);
+    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);
+    if (fd < 0) {
+        fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n");
+        return -1;
+    }
+    memset(&ifr, 0, sizeof(ifr));
+    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+    if (ifname[0] != '\0')
+        pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);
+    else
+        pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d");
+    ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
+    if (ret != 0) {
+        fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n");
+        close(fd);
+        return -1;
+    }
+    pstrcpy(ifname, ifname_size, ifr.ifr_name);
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+    return fd;
+}
+#endif
+
+static int net_tap_init(VLANState *vlan, const char *ifname1,
+                        const char *setup_script)
+{
+    TAPState *s;
+    int pid, status, fd;
+    char *args[3];
+    char **parg;
+    char ifname[128];
+
+    if (ifname1 != NULL)
+        pstrcpy(ifname, sizeof(ifname), ifname1);
+    else
+        ifname[0] = '\0';
+    fd = tap_open(ifname, sizeof(ifname));
+    if (fd < 0)
+        return -1;
+
+    if (!setup_script)
+        setup_script = "";
+    if (setup_script[0] != '\0') {
+        /* try to launch network init script */
+        pid = fork();
+        if (pid >= 0) {
+            if (pid == 0) {
+                parg = args;
+                *parg++ = (char *)setup_script;
+                *parg++ = ifname;
+                *parg++ = NULL;
+                execv(setup_script, args);
+                _exit(1);
+            }
+            while (waitpid(pid, &status, 0) != pid);
+            if (!WIFEXITED(status) ||
+                WEXITSTATUS(status) != 0) {
+                fprintf(stderr, "%s: could not launch network script\n",
+                        setup_script);
+                return -1;
+            }
+        }
+    }
+    s = net_tap_fd_init(vlan, fd);
+    if (!s)
+        return -1;
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str), 
+             "tap: ifname=%s setup_script=%s", ifname, setup_script);
+    return 0;
+}
+
+/* network connection */
+typedef struct NetSocketState {
+    VLANClientState *vc;
+    int fd;
+    int state; /* 0 = getting length, 1 = getting data */
+    int index;
+    int packet_len;
+    uint8_t buf[4096];
+    struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
+} NetSocketState;
+
+typedef struct NetSocketListenState {
+    VLANState *vlan;
+    int fd;
+} NetSocketListenState;
+
+/* XXX: we consider we can send the whole packet without blocking */
+static void net_socket_receive(void *opaque, const uint8_t *buf, int size)
+{
+    NetSocketState *s = opaque;
+    uint32_t len;
+    len = htonl(size);
+
+    unix_write(s->fd, (const uint8_t *)&len, sizeof(len));
+    unix_write(s->fd, buf, size);
+}
+
+static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size)
+{
+    NetSocketState *s = opaque;
+    sendto(s->fd, buf, size, 0, 
+           (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
+}
+
+static void net_socket_send(void *opaque)
+{
+    NetSocketState *s = opaque;
+    int l, size;
+    uint8_t buf1[4096];
+    const uint8_t *buf;
+
+    size = read(s->fd, buf1, sizeof(buf1));
+    if (size < 0) 
+        return;
+    if (size == 0) {
+        /* end of connection */
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        return;
+    }
+    buf = buf1;
+    while (size > 0) {
+        /* reassemble a packet from the network */
+        switch(s->state) {
+        case 0:
+            l = 4 - s->index;
+            if (l > size)
+                l = size;
+            memcpy(s->buf + s->index, buf, l);
+            buf += l;
+            size -= l;
+            s->index += l;
+            if (s->index == 4) {
+                /* got length */
+                s->packet_len = ntohl(*(uint32_t *)s->buf);
+                s->index = 0;
+                s->state = 1;
+            }
+            break;
+        case 1:
+            l = s->packet_len - s->index;
+            if (l > size)
+                l = size;
+            memcpy(s->buf + s->index, buf, l);
+            s->index += l;
+            buf += l;
+            size -= l;
+            if (s->index >= s->packet_len) {
+                qemu_send_packet(s->vc, s->buf, s->packet_len);
+                s->index = 0;
+                s->state = 0;
+            }
+            break;
+        }
+    }
+}
+
+static void net_socket_send_dgram(void *opaque)
+{
+    NetSocketState *s = opaque;
+    int size;
+
+    size = recv(s->fd, s->buf, sizeof(s->buf), 0);
+    if (size < 0) 
+        return;
+    if (size == 0) {
+        /* end of connection */
+        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+        return;
+    }
+    qemu_send_packet(s->vc, s->buf, size);
+}
+
+static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
+{
+    struct ip_mreq imr;
+    int fd;
+    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), ntohl(mcastaddr->sin_addr.s_addr));
+       return -1;
+
+    }
+    fd = socket(PF_INET, SOCK_DGRAM, 0);
+    if (fd < 0) {
+        perror("socket(PF_INET, SOCK_DGRAM)");
+        return -1;
+    }
+
+    /* 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, (void *) &imr, sizeof(struct ip_mreq));
+    if (ret < 0) {
+       perror("setsockopt(IP_ADD_MEMBERSHIP)");
+       goto fail;
+    }
+
+    /* Force mcast msgs to loopback (eg. several QEMUs in same host */
+    val = 1;
+    ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &val, sizeof(val));
+    if (ret < 0) {
+       perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
+       goto fail;
+    }
+
+    ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+    if (ret < 0) {
+       perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
+       goto fail;
+    }
+    
+    ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
+    if (ret < 0) {
+        perror("bind");
+        goto fail;
+    }
+    
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+    return fd;
+fail:
+    if (fd>=0) close(fd);
+    return -1;
+}
+
+static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd, 
+                                          int is_connected)
+{
+    struct sockaddr_in saddr;
+    int newfd;
+    socklen_t saddr_len;
+    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() 
+     * by ONLY ONE process: we must "clone" this dgram socket --jjo
+     */
+
+    if (is_connected) {
+       if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
+           /* must be bound */
+           if (saddr.sin_addr.s_addr==0) {
+               fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
+                       fd);
+               return NULL;
+           }
+           /* clone dgram socket */
+           newfd = net_socket_mcast_create(&saddr);
+           if (newfd < 0) {
+               /* error already reported by net_socket_mcast_create() */
+               close(fd);
+               return NULL;
+           }
+           /* 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));
+           return NULL;
+       }
+    }
+
+    s = qemu_mallocz(sizeof(NetSocketState));
+    if (!s)
+        return NULL;
+    s->fd = fd;
+
+    s->vc = qemu_new_vlan_client(vlan, net_socket_receive_dgram, s);
+    qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
+
+    /* mcast: save bound address as dst */
+    if (is_connected) s->dgram_dst=saddr;
+
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+           "socket: fd=%d (%s mcast=%s:%d)", 
+           fd, is_connected? "cloned" : "",
+           inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+    return s;
+}
+
+static void net_socket_connect(void *opaque)
+{
+    NetSocketState *s = opaque;
+    qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
+}
+
+static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd, 
+                                          int is_connected)
+{
+    NetSocketState *s;
+    s = qemu_mallocz(sizeof(NetSocketState));
+    if (!s)
+        return NULL;
+    s->fd = fd;
+    s->vc = qemu_new_vlan_client(vlan, 
+                                 net_socket_receive, s);
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "socket: fd=%d", fd);
+    if (is_connected) {
+        net_socket_connect(s);
+    } else {
+        qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
+    }
+    return s;
+}
+
+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, &so_type, &optlen)< 0) {
+       fprintf(stderr, "qemu: error: setsockopt(SO_TYPE) for fd=%d failed\n", fd);
+       return NULL;
+    }
+    switch(so_type) {
+    case SOCK_DGRAM:
+        return net_socket_fd_init_dgram(vlan, fd, is_connected);
+    case SOCK_STREAM:
+        return net_socket_fd_init_stream(vlan, fd, is_connected);
+    default:
+        /* who knows ... this could be a eg. a pty, do warn and continue as stream */
+        fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
+        return net_socket_fd_init_stream(vlan, fd, is_connected);
+    }
+    return NULL;
+}
+
+static void net_socket_accept(void *opaque)
+{
+    NetSocketListenState *s = opaque;    
+    NetSocketState *s1;
+    struct sockaddr_in saddr;
+    socklen_t len;
+    int fd;
+
+    for(;;) {
+        len = sizeof(saddr);
+        fd = accept(s->fd, (struct sockaddr *)&saddr, &len);
+        if (fd < 0 && errno != EINTR) {
+            return;
+        } else if (fd >= 0) {
+            break;
+        }
+    }
+    s1 = net_socket_fd_init(s->vlan, fd, 1); 
+    if (!s1) {
+        close(fd);
+    } else {
+        snprintf(s1->vc->info_str, sizeof(s1->vc->info_str),
+                 "socket: connection from %s:%d", 
+                 inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+    }
+}
+
+static int net_socket_listen_init(VLANState *vlan, const char *host_str)
+{
+    NetSocketListenState *s;
+    int fd, val, ret;
+    struct sockaddr_in saddr;
+
+    if (parse_host_port(&saddr, host_str) < 0)
+        return -1;
+    
+    s = qemu_mallocz(sizeof(NetSocketListenState));
+    if (!s)
+        return -1;
+
+    fd = socket(PF_INET, SOCK_STREAM, 0);
+    if (fd < 0) {
+        perror("socket");
+        return -1;
+    }
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+
+    /* allow fast reuse */
+    val = 1;
+    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+    
+    ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
+    if (ret < 0) {
+        perror("bind");
+        return -1;
+    }
+    ret = listen(fd, 0);
+    if (ret < 0) {
+        perror("listen");
+        return -1;
+    }
+    s->vlan = vlan;
+    s->fd = fd;
+    qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
+    return 0;
+}
+
+static int net_socket_connect_init(VLANState *vlan, const char *host_str)
+{
+    NetSocketState *s;
+    int fd, connected, ret;
+    struct sockaddr_in saddr;
+
+    if (parse_host_port(&saddr, host_str) < 0)
+        return -1;
+
+    fd = socket(PF_INET, SOCK_STREAM, 0);
+    if (fd < 0) {
+        perror("socket");
+        return -1;
+    }
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+
+    connected = 0;
+    for(;;) {
+        ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
+        if (ret < 0) {
+            if (errno == EINTR || errno == EAGAIN) {
+            } else if (errno == EINPROGRESS) {
+                break;
+            } else {
+                perror("connect");
+                close(fd);
+                return -1;
+            }
+        } else {
+            connected = 1;
+            break;
+        }
+    }
+    s = net_socket_fd_init(vlan, fd, connected);
+    if (!s)
+        return -1;
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "socket: connect to %s:%d", 
+             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+    return 0;
+}
+
+static int net_socket_mcast_init(VLANState *vlan, const char *host_str)
+{
+    NetSocketState *s;
+    int fd;
+    struct sockaddr_in saddr;
+
+    if (parse_host_port(&saddr, host_str) < 0)
+        return -1;
+
+
+    fd = net_socket_mcast_create(&saddr);
+    if (fd < 0)
+       return -1;
+
+    s = net_socket_fd_init(vlan, fd, 0);
+    if (!s)
+        return -1;
+
+    s->dgram_dst = saddr;
+    
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "socket: mcast=%s:%d", 
+             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+    return 0;
+
+}
+
+#endif /* !_WIN32 */
+
+static int get_param_value(char *buf, int buf_size,
+                           const char *tag, const char *str)
+{
+    const char *p;
+    char *q;
+    char option[128];
+
+    p = str;
+    for(;;) {
+        q = option;
+        while (*p != '\0' && *p != '=') {
+            if ((q - option) < sizeof(option) - 1)
+                *q++ = *p;
+            p++;
+        }
+        *q = '\0';
+        if (*p != '=')
+            break;
+        p++;
+        if (!strcmp(tag, option)) {
+            q = buf;
+            while (*p != '\0' && *p != ',') {
+                if ((q - buf) < buf_size - 1)
+                    *q++ = *p;
+                p++;
+            }
+            *q = '\0';
+            return q - buf;
+        } else {
+            while (*p != '\0' && *p != ',') {
+                p++;
+            }
+        }
+        if (*p != ',')
+            break;
+        p++;
+    }
+    return 0;
+}
+
+int net_client_init(const char *str)
+{
+    const char *p;
+    char *q;
+    char device[64];
+    char buf[1024];
+    int vlan_id, ret;
+    VLANState *vlan;
+
+    p = str;
+    q = device;
+    while (*p != '\0' && *p != ',') {
+        if ((q - device) < sizeof(device) - 1)
+            *q++ = *p;
+        p++;
+    }
+    *q = '\0';
+    if (*p == ',')
+        p++;
+    vlan_id = 0;
+    if (get_param_value(buf, sizeof(buf), "vlan", p)) {
+        vlan_id = strtol(buf, NULL, 0);
+    }
+    vlan = qemu_find_vlan(vlan_id);
+    if (!vlan) {
+        fprintf(stderr, "Could not create vlan %d\n", vlan_id);
+        return -1;
+    }
+    if (!strcmp(device, "nic")) {
+        NICInfo *nd;
+        uint8_t *macaddr;
+
+        if (nb_nics >= MAX_NICS) {
+            fprintf(stderr, "Too Many NICs\n");
+            return -1;
+        }
+        nd = &nd_table[nb_nics];
+        macaddr = nd->macaddr;
+        macaddr[0] = 0x52;
+        macaddr[1] = 0x54;
+        macaddr[2] = 0x00;
+        macaddr[3] = 0x12;
+        macaddr[4] = 0x34;
+        macaddr[5] = 0x56 + nb_nics;
+
+        if (get_param_value(buf, sizeof(buf), "macaddr", p)) {
+            if (parse_macaddr(macaddr, buf) < 0) {
+                fprintf(stderr, "invalid syntax for ethernet address\n");
+                return -1;
+            }
+        }
+        nd->vlan = vlan;
+        nb_nics++;
+        ret = 0;
+    } else
+    if (!strcmp(device, "none")) {
+        /* does nothing. It is needed to signal that no network cards
+           are wanted */
+        ret = 0;
+    } else
+#ifdef CONFIG_SLIRP
+    if (!strcmp(device, "user")) {
+        ret = net_slirp_init(vlan);
+    } else
+#endif
+#ifndef _WIN32
+    if (!strcmp(device, "tap")) {
+        char ifname[64];
+        char setup_script[1024];
+        int fd;
+        if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
+            fd = strtol(buf, NULL, 0);
+            ret = -1;
+            if (net_tap_fd_init(vlan, fd))
+                ret = 0;
+        } else {
+            get_param_value(ifname, sizeof(ifname), "ifname", p);
+            if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) {
+                pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT);
+            }
+            ret = net_tap_init(vlan, ifname, setup_script);
+        }
+    } else
+    if (!strcmp(device, "socket")) {
+        if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
+            int fd;
+            fd = strtol(buf, NULL, 0);
+            ret = -1;
+            if (net_socket_fd_init(vlan, fd, 1))
+                ret = 0;
+        } else if (get_param_value(buf, sizeof(buf), "listen", p) > 0) {
+            ret = net_socket_listen_init(vlan, buf);
+        } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) {
+            ret = net_socket_connect_init(vlan, buf);
+        } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) {
+            ret = net_socket_mcast_init(vlan, buf);
+        } else {
+            fprintf(stderr, "Unknown socket options: %s\n", p);
+            return -1;
+        }
+    } else
+#endif
+    {
+        fprintf(stderr, "Unknown network device: %s\n", device);
+        return -1;
+    }
+    if (ret < 0) {
+        fprintf(stderr, "Could not initialize device '%s'\n", device);
+    }
+    
+    return ret;
 }
 
-#endif /* !defined(_WIN32) */
+void do_info_network(void)
+{
+    VLANState *vlan;
+    VLANClientState *vc;
 
-#endif /* CONFIG_SLIRP */
+    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+        term_printf("VLAN %d devices:\n", vlan->id);
+        for(vc = vlan->first_client; vc != NULL; vc = vc->next)
+            term_printf("  %s\n", vc->info_str);
+    }
+}
+/***********************************************************/
+/* USB devices */
 
-#if !defined(_WIN32)
-#ifdef _BSD
-static int tun_open(char *ifname, int ifname_size)
+static int usb_device_add(const char *devname)
 {
-    int fd;
-    char *dev;
-    struct stat s;
+    const char *p;
+    USBDevice *dev;
+    int i;
 
-    fd = open("/dev/tap", O_RDWR);
-    if (fd < 0) {
-        fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n");
+    if (!vm_usb_hub)
         return -1;
+    for(i = 0;i < MAX_VM_USB_PORTS; i++) {
+        if (!vm_usb_ports[i]->dev)
+            break;
     }
+    if (i == MAX_VM_USB_PORTS)
+        return -1;
 
-    fstat(fd, &s);
-    dev = devname(s.st_rdev, S_IFCHR);
-    pstrcpy(ifname, ifname_size, dev);
-
-    fcntl(fd, F_SETFL, O_NONBLOCK);
-    return fd;
+    if (strstart(devname, "host:", &p)) {
+        dev = usb_host_device_open(p);
+        if (!dev)
+            return -1;
+    } else if (!strcmp(devname, "mouse")) {
+        dev = usb_mouse_init();
+        if (!dev)
+            return -1;
+    } else {
+        return -1;
+    }
+    usb_attach(vm_usb_ports[i], dev);
+    return 0;
 }
-#else
-static int tun_open(char *ifname, int ifname_size)
+
+static int usb_device_del(const char *devname)
 {
-    struct ifreq ifr;
-    int fd, ret;
-    
-    fd = open("/dev/net/tun", O_RDWR);
-    if (fd < 0) {
-        fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n");
+    USBDevice *dev;
+    int bus_num, addr, i;
+    const char *p;
+
+    if (!vm_usb_hub)
         return -1;
-    }
-    memset(&ifr, 0, sizeof(ifr));
-    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
-    pstrcpy(ifr.ifr_name, IFNAMSIZ, "tun%d");
-    ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
-    if (ret != 0) {
-        fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n");
-        close(fd);
+
+    p = strchr(devname, '.');
+    if (!p) 
+        return -1;
+    bus_num = strtoul(devname, NULL, 0);
+    addr = strtoul(p + 1, NULL, 0);
+    if (bus_num != 0)
         return -1;
+    for(i = 0;i < MAX_VM_USB_PORTS; i++) {
+        dev = vm_usb_ports[i]->dev;
+        if (dev && dev->addr == addr)
+            break;
     }
-    printf("Connected to host network interface: %s\n", ifr.ifr_name);
-    pstrcpy(ifname, ifname_size, ifr.ifr_name);
-    fcntl(fd, F_SETFL, O_NONBLOCK);
-    return fd;
+    if (i == MAX_VM_USB_PORTS)
+        return -1;
+    usb_attach(vm_usb_ports[i], NULL);
+    return 0;
 }
-#endif
 
-static void tun_send_packet(NetDriverState *nd, const uint8_t *buf, int size)
+void do_usb_add(const char *devname)
 {
-    write(nd->fd, buf, size);
+    int ret;
+    ret = usb_device_add(devname);
+    if (ret < 0) 
+        term_printf("Could not add USB device '%s'\n", devname);
 }
 
-static void tun_add_read_packet(NetDriverState *nd, 
-                                IOCanRWHandler *fd_can_read, 
-                                IOReadHandler *fd_read, void *opaque)
+void do_usb_del(const char *devname)
 {
-    qemu_add_fd_read_handler(nd->fd, fd_can_read, fd_read, opaque);
+    int ret;
+    ret = usb_device_del(devname);
+    if (ret < 0) 
+        term_printf("Could not remove USB device '%s'\n", devname);
 }
 
-static int net_tun_init(NetDriverState *nd)
+void usb_info(void)
 {
-    int pid, status;
-    char *args[3];
-    char **parg;
+    USBDevice *dev;
+    int i;
+    const char *speed_str;
 
-    nd->fd = tun_open(nd->ifname, sizeof(nd->ifname));
-    if (nd->fd < 0)
-        return -1;
+    if (!vm_usb_hub) {
+        term_printf("USB support not enabled\n");
+        return;
+    }
 
-    /* try to launch network init script */
-    pid = fork();
-    if (pid >= 0) {
-        if (pid == 0) {
-            parg = args;
-            *parg++ = network_script;
-            *parg++ = nd->ifname;
-            *parg++ = NULL;
-            execv(network_script, args);
-            exit(1);
-        }
-        while (waitpid(pid, &status, 0) != pid);
-        if (!WIFEXITED(status) ||
-            WEXITSTATUS(status) != 0) {
-            fprintf(stderr, "%s: could not launch network script\n",
-                    network_script);
+    for(i = 0; i < MAX_VM_USB_PORTS; i++) {
+        dev = vm_usb_ports[i]->dev;
+        if (dev) {
+            term_printf("Hub port %d:\n", i);
+            switch(dev->speed) {
+            case USB_SPEED_LOW: 
+                speed_str = "1.5"; 
+                break;
+            case USB_SPEED_FULL: 
+                speed_str = "12"; 
+                break;
+            case USB_SPEED_HIGH: 
+                speed_str = "480"; 
+                break;
+            default:
+                speed_str = "?"; 
+                break;
+            }
+            term_printf("  Device %d.%d, speed %s Mb/s\n", 
+                        0, dev->addr, speed_str);
         }
     }
-    nd->send_packet = tun_send_packet;
-    nd->add_read_packet = tun_add_read_packet;
-    return 0;
-}
-
-static int net_fd_init(NetDriverState *nd, int fd)
-{
-    nd->fd = fd;
-    nd->send_packet = tun_send_packet;
-    nd->add_read_packet = tun_add_read_packet;
-    pstrcpy(nd->ifname, sizeof(nd->ifname), "tunfd");
-    return 0;
 }
 
-#endif /* !_WIN32 */
-
 /***********************************************************/
 /* pid file */
 
@@ -1820,49 +2889,65 @@ static void host_segv_handler(int host_signum, siginfo_t *info,
 
 typedef struct IOHandlerRecord {
     int fd;
-    IOCanRWHandler *fd_can_read;
-    IOReadHandler *fd_read;
+    IOCanRWHandler *fd_read_poll;
+    IOHandler *fd_read;
+    IOHandler *fd_write;
     void *opaque;
     /* temporary data */
     struct pollfd *ufd;
-    int max_size;
     struct IOHandlerRecord *next;
 } IOHandlerRecord;
 
 static IOHandlerRecord *first_io_handler;
 
-int qemu_add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, 
-                             IOReadHandler *fd_read, void *opaque)
+/* 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, 
+                         void *opaque)
 {
-    IOHandlerRecord *ioh;
+    IOHandlerRecord **pioh, *ioh;
 
-    ioh = qemu_mallocz(sizeof(IOHandlerRecord));
-    if (!ioh)
-        return -1;
-    ioh->fd = fd;
-    ioh->fd_can_read = fd_can_read;
-    ioh->fd_read = fd_read;
-    ioh->opaque = opaque;
-    ioh->next = first_io_handler;
-    first_io_handler = ioh;
+    if (!fd_read && !fd_write) {
+        pioh = &first_io_handler;
+        for(;;) {
+            ioh = *pioh;
+            if (ioh == NULL)
+                break;
+            if (ioh->fd == fd) {
+                *pioh = ioh->next;
+                break;
+            }
+            pioh = &ioh->next;
+        }
+    } else {
+        for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
+            if (ioh->fd == fd)
+                goto found;
+        }
+        ioh = qemu_mallocz(sizeof(IOHandlerRecord));
+        if (!ioh)
+            return -1;
+        ioh->next = first_io_handler;
+        first_io_handler = ioh;
+    found:
+        ioh->fd = fd;
+        ioh->fd_read_poll = fd_read_poll;
+        ioh->fd_read = fd_read;
+        ioh->fd_write = fd_write;
+        ioh->opaque = opaque;
+    }
     return 0;
 }
 
-void qemu_del_fd_read_handler(int fd)
+int qemu_set_fd_handler(int fd, 
+                        IOHandler *fd_read, 
+                        IOHandler *fd_write, 
+                        void *opaque)
 {
-    IOHandlerRecord **pioh, *ioh;
-
-    pioh = &first_io_handler;
-    for(;;) {
-        ioh = *pioh;
-        if (ioh == NULL)
-            break;
-        if (ioh->fd == fd) {
-            *pioh = ioh->next;
-            break;
-        }
-        pioh = &ioh->next;
-    }
+    return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
 }
 
 /***********************************************************/
@@ -2084,9 +3169,6 @@ int qemu_loadvm(const char *filename)
         goto the_end;
     }
     for(;;) {
-#if defined (DO_TB_FLUSH)
-        tb_flush(global_env);
-#endif
         len = qemu_get_byte(f);
         if (feof(f))
             break;
@@ -2472,6 +3554,19 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     tlb_flush(env, 1);
     return 0;
 }
+
+#elif defined(TARGET_ARM)
+
+/* ??? Need to implement these.  */
+void cpu_save(QEMUFile *f, void *opaque)
+{
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return 0;
+}
+
 #else
 
 #warning No CPU save/restore functions
@@ -2580,9 +3675,47 @@ void gui_update(void *opaque)
     qemu_mod_timer(gui_timer, GUI_REFRESH_INTERVAL + qemu_get_clock(rt_clock));
 }
 
+struct vm_change_state_entry {
+    VMChangeStateHandler *cb;
+    void *opaque;
+    LIST_ENTRY (vm_change_state_entry) entries;
+};
+
+static LIST_HEAD(vm_change_state_head, vm_change_state_entry) vm_change_state_head;
+
+VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
+                                                     void *opaque)
+{
+    VMChangeStateEntry *e;
+
+    e = qemu_mallocz(sizeof (*e));
+    if (!e)
+        return NULL;
+
+    e->cb = cb;
+    e->opaque = opaque;
+    LIST_INSERT_HEAD(&vm_change_state_head, e, entries);
+    return e;
+}
+
+void qemu_del_vm_change_state_handler(VMChangeStateEntry *e)
+{
+    LIST_REMOVE (e, entries);
+    qemu_free (e);
+}
+
+static void vm_state_notify(int running)
+{
+    VMChangeStateEntry *e;
+
+    for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {
+        e->cb(e->opaque, running);
+    }
+}
+
 /* XXX: support several handlers */
-VMStopHandler *vm_stop_cb;
-VMStopHandler *vm_stop_opaque;
+static VMStopHandler *vm_stop_cb;
+static void *vm_stop_opaque;
 
 int qemu_add_vm_stop_handler(VMStopHandler *cb, void *opaque)
 {
@@ -2601,6 +3734,7 @@ void vm_start(void)
     if (!vm_running) {
         cpu_enable_ticks();
         vm_running = 1;
+        vm_state_notify(1);
     }
 }
 
@@ -2614,6 +3748,7 @@ void vm_stop(int reason)
                 vm_stop_cb(vm_stop_opaque, reason);
             }
         }
+        vm_state_notify(0);
     }
 }
 
@@ -2657,27 +3792,22 @@ void qemu_system_reset(void)
 void qemu_system_reset_request(void)
 {
     reset_requested = 1;
-    cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
+    if (cpu_single_env)
+        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
 }
 
 void qemu_system_shutdown_request(void)
 {
     shutdown_requested = 1;
-    cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
+    if (cpu_single_env)
+        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
 }
 
 void qemu_system_powerdown_request(void)
 {
     powerdown_requested = 1;
-    cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
-}
-
-static void main_cpu_reset(void *opaque)
-{
-#if defined(TARGET_I386) || defined(TARGET_SPARC)
-    CPUState *env = opaque;
-    cpu_reset(env);
-#endif
+    if (cpu_single_env)
+        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
 }
 
 void main_loop_wait(int timeout)
@@ -2685,8 +3815,6 @@ void main_loop_wait(int timeout)
 #ifndef _WIN32
     struct pollfd ufds[MAX_IO_HANDLERS + 1], *pf;
     IOHandlerRecord *ioh, *ioh_next;
-    uint8_t buf[4096];
-    int n, max_size;
 #endif
     int ret;
 
@@ -2698,26 +3826,18 @@ void main_loop_wait(int timeout)
         /* XXX: separate device handlers from system ones */
         pf = ufds;
         for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
-            if (!ioh->fd_can_read) {
-                max_size = 0;
-                pf->fd = ioh->fd;
-                pf->events = POLLIN;
-                ioh->ufd = pf;
-                pf++;
-            } else {
-                max_size = ioh->fd_can_read(ioh->opaque);
-                if (max_size > 0) {
-                    if (max_size > sizeof(buf))
-                        max_size = sizeof(buf);
-                    pf->fd = ioh->fd;
-                    pf->events = POLLIN;
-                    ioh->ufd = pf;
-                    pf++;
-                } else {
-                    ioh->ufd = NULL;
-                }
+            pf->events = 0;
+            pf->fd = ioh->fd;
+            if (ioh->fd_read &&
+                (!ioh->fd_read_poll ||
+                 ioh->fd_read_poll(ioh->opaque) != 0)) {
+                pf->events |= POLLIN;
+            }
+            if (ioh->fd_write) {
+                pf->events |= POLLOUT;
             }
-            ioh->max_size = max_size;
+            ioh->ufd = pf;
+            pf++;
         }
         
         ret = poll(ufds, pf - ufds, timeout);
@@ -2726,20 +3846,11 @@ void main_loop_wait(int timeout)
             for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) {
                 ioh_next = ioh->next;
                 pf = ioh->ufd;
-                if (pf) {
-                    if (pf->revents & POLLIN) {
-                        if (ioh->max_size == 0) {
-                            /* just a read event */
-                            ioh->fd_read(ioh->opaque, NULL, 0);
-                        } else {
-                            n = read(ioh->fd, buf, ioh->max_size);
-                            if (n >= 0) {
-                                ioh->fd_read(ioh->opaque, buf, n);
-                            } else if (errno != EAGAIN) {
-                                ioh->fd_read(ioh->opaque, NULL, -errno);
-                            }
-                        }
-                    }
+                if (pf->revents & POLLIN) {
+                    ioh->fd_read(ioh->opaque);
+                }
+                if (pf->revents & POLLOUT) {
+                    ioh->fd_write(ioh->opaque);
                 }
             }
         }
@@ -2777,14 +3888,34 @@ void main_loop_wait(int timeout)
                         qemu_get_clock(rt_clock));
 }
 
+static CPUState *cur_cpu;
+
 int main_loop(void)
 {
     int ret, timeout;
-    CPUState *env = global_env;
+    CPUState *env;
 
+    cur_cpu = first_cpu;
     for(;;) {
         if (vm_running) {
-            ret = cpu_exec(env);
+
+            env = cur_cpu;
+            for(;;) {
+                /* get next cpu */
+                env = env->next_cpu;
+                if (!env)
+                    env = first_cpu;
+                ret = cpu_exec(env);
+                if (ret != EXCP_HALTED)
+                    break;
+                /* all CPUs are halted ? */
+                if (env == cur_cpu) {
+                    ret = EXCP_HLT;
+                    break;
+                }
+            }
+            cur_cpu = env;
+
             if (shutdown_requested) {
                 ret = EXCP_INTERRUPT;
                 break;
@@ -2833,35 +3964,57 @@ void help(void)
            "-boot [a|c|d]   boot on floppy (a), hard disk (c) or CD-ROM (d)\n"
           "-snapshot       write to temporary files instead of disk image files\n"
            "-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"
 #ifndef _WIN32
           "-k language     use keyboard layout (for example \"fr\" for French)\n"
 #endif
-           "-enable-audio   enable audio support\n"
+#ifdef HAS_AUDIO
+           "-audio-help     print list of audio drivers and their options\n"
+           "-soundhw c1,... enable audio support\n"
+           "                and only specified sound cards (comma separated list)\n"
+           "                use -soundhw ? to get the list of supported cards\n"
+           "                use -soundhw all to enable all of them\n"
+#endif
            "-localtime      set the real time clock to local time [default=utc]\n"
            "-full-screen    start in full screen\n"
 #ifdef TARGET_I386
            "-win2k-hack     use it when installing Windows 2000 to avoid a disk full bug\n"
 #endif
+           "-usb            enable the USB driver (will be the default soon)\n"
+           "-usbdevice name add the host or guest USB device 'name'\n"
 #if defined(TARGET_PPC) || defined(TARGET_SPARC)
            "-g WxH[xDEPTH]  Set the initial graphical resolution and depth\n"
 #endif
            "\n"
            "Network options:\n"
-           "-nics n         simulate 'n' network cards [default=1]\n"
-           "-macaddr addr   set the mac address of the first interface\n"
-           "-n script       set tap/tun network init script [default=%s]\n"
-           "-tun-fd fd      use this fd as already opened tap/tun interface\n"
+           "-net nic[,vlan=n][,macaddr=addr]\n"
+           "                create a new Network Interface Card and connect it to VLAN 'n'\n"
+#ifdef CONFIG_SLIRP
+           "-net user[,vlan=n]\n"
+           "                connect the user mode network stack to VLAN 'n'\n"
+#endif
+#ifndef _WIN32
+           "-net tap[,vlan=n][,fd=h][,ifname=name][,script=file]\n"
+           "                connect the host TAP network interface to VLAN 'n' and use\n"
+           "                the network script 'file' (default=%s);\n"
+           "                use 'fd=h' to connect to an already opened TAP interface\n"
+           "-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\n"
+           "                connect the vlan 'n' to another VLAN using a socket connection\n"
+           "-net socket[,vlan=n][,fd=h][,mcast=maddr:port]\n"
+           "                connect the vlan 'n' to multicast maddr and port\n"
+#endif
+           "-net none       use it alone to have zero network devices; if no -net option\n"
+           "                is provided, the default is '-net nic -net user'\n"
+           "\n"
 #ifdef CONFIG_SLIRP
-           "-user-net       use user mode network stack [default if no tap/tun script]\n"
-           "-tftp prefix    allow tftp access to files starting with prefix [-user-net]\n"
+           "-tftp prefix    allow tftp access to files starting with prefix [-net user]\n"
 #ifndef _WIN32
-           "-smb dir        allow SMB access to files in 'dir' [-user-net]\n"
+           "-smb dir        allow SMB access to files in 'dir' [-net user]\n"
 #endif
            "-redir [tcp|udp]:host-port:[guest-host]:guest-port\n"
-           "                redirect TCP or UDP connections from host to guest [-user-net]\n"
+           "                redirect TCP or UDP connections from host to guest [-net user]\n"
 #endif
-           "-dummy-net      use dummy network stack\n"
            "\n"
            "Linux boot specific:\n"
            "-kernel bzImage use 'bzImage' as kernel image\n"
@@ -2887,7 +4040,6 @@ void help(void)
            "-no-code-copy   disable code copy acceleration\n"
 #endif
 #ifdef TARGET_I386
-           "-isa            simulate an ISA-only system (default is PCI system)\n"
            "-std-vga        simulate a standard VGA card with VESA Bochs Extensions\n"
            "                (default is CL-GD5446 PCI VGA)\n"
 #endif
@@ -2906,7 +4058,9 @@ void help(void)
            "qemu-fast",
 #endif
            DEFAULT_RAM_SIZE,
+#ifndef _WIN32
            DEFAULT_NETWORK_SCRIPT,
+#endif
            DEFAULT_GDBSTUB_PORT,
            "/tmp/qemu.log");
 #ifndef CONFIG_SOFTMMU
@@ -2935,17 +4089,15 @@ enum {
     QEMU_OPTION_snapshot,
     QEMU_OPTION_m,
     QEMU_OPTION_nographic,
-    QEMU_OPTION_enable_audio,
+#ifdef HAS_AUDIO
+    QEMU_OPTION_audio_help,
+    QEMU_OPTION_soundhw,
+#endif
 
-    QEMU_OPTION_nics,
-    QEMU_OPTION_macaddr,
-    QEMU_OPTION_n,
-    QEMU_OPTION_tun_fd,
-    QEMU_OPTION_user_net,
+    QEMU_OPTION_net,
     QEMU_OPTION_tftp,
     QEMU_OPTION_smb,
     QEMU_OPTION_redir,
-    QEMU_OPTION_dummy_net,
 
     QEMU_OPTION_kernel,
     QEMU_OPTION_append,
@@ -2958,9 +4110,6 @@ enum {
     QEMU_OPTION_hdachs,
     QEMU_OPTION_L,
     QEMU_OPTION_no_code_copy,
-    QEMU_OPTION_pci,
-    QEMU_OPTION_isa,
-    QEMU_OPTION_prep,
     QEMU_OPTION_k,
     QEMU_OPTION_localtime,
     QEMU_OPTION_cirrusvga,
@@ -2974,6 +4123,9 @@ enum {
     QEMU_OPTION_pidfile,
     QEMU_OPTION_no_kqemu,
     QEMU_OPTION_win2k_hack,
+    QEMU_OPTION_usb,
+    QEMU_OPTION_usbdevice,
+    QEMU_OPTION_smp,
 };
 
 typedef struct QEMUOption {
@@ -2998,21 +4150,19 @@ const QEMUOption qemu_options[] = {
     { "m", HAS_ARG, QEMU_OPTION_m },
     { "nographic", 0, QEMU_OPTION_nographic },
     { "k", HAS_ARG, QEMU_OPTION_k },
-    { "enable-audio", 0, QEMU_OPTION_enable_audio },
+#ifdef HAS_AUDIO
+    { "audio-help", 0, QEMU_OPTION_audio_help },
+    { "soundhw", HAS_ARG, QEMU_OPTION_soundhw },
+#endif
 
-    { "nics", HAS_ARG, QEMU_OPTION_nics},
-    { "macaddr", HAS_ARG, QEMU_OPTION_macaddr},
-    { "n", HAS_ARG, QEMU_OPTION_n },
-    { "tun-fd", HAS_ARG, QEMU_OPTION_tun_fd },
+    { "net", HAS_ARG, QEMU_OPTION_net},
 #ifdef CONFIG_SLIRP
-    { "user-net", 0, QEMU_OPTION_user_net },
     { "tftp", HAS_ARG, QEMU_OPTION_tftp },
 #ifndef _WIN32
     { "smb", HAS_ARG, QEMU_OPTION_smb },
 #endif
     { "redir", HAS_ARG, QEMU_OPTION_redir },
 #endif
-    { "dummy-net", 0, QEMU_OPTION_dummy_net },
 
     { "kernel", HAS_ARG, QEMU_OPTION_kernel },
     { "append", HAS_ARG, QEMU_OPTION_append },
@@ -3028,14 +4178,10 @@ const QEMUOption qemu_options[] = {
 #ifdef USE_KQEMU
     { "no-kqemu", 0, QEMU_OPTION_no_kqemu },
 #endif
-#ifdef TARGET_PPC
-    { "prep", 0, QEMU_OPTION_prep },
-#endif
 #if defined(TARGET_PPC) || defined(TARGET_SPARC)
     { "g", 1, QEMU_OPTION_g },
 #endif
     { "localtime", 0, QEMU_OPTION_localtime },
-    { "isa", 0, QEMU_OPTION_isa },
     { "std-vga", 0, QEMU_OPTION_std_vga },
     { "monitor", 1, QEMU_OPTION_monitor },
     { "serial", 1, QEMU_OPTION_serial },
@@ -3044,9 +4190,11 @@ const QEMUOption qemu_options[] = {
     { "full-screen", 0, QEMU_OPTION_full_screen },
     { "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
     { "win2k-hack", 0, QEMU_OPTION_win2k_hack },
+    { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice },
+    { "smp", HAS_ARG, QEMU_OPTION_smp },
     
     /* temporary options */
-    { "pci", 0, QEMU_OPTION_pci },
+    { "usb", 0, QEMU_OPTION_usb },
     { "cirrusvga", 0, QEMU_OPTION_cirrusvga },
     { NULL },
 };
@@ -3102,6 +4250,7 @@ void register_machines(void)
 {
 #if defined(TARGET_I386)
     qemu_register_machine(&pc_machine);
+    qemu_register_machine(&isapc_machine);
 #elif defined(TARGET_PPC)
     qemu_register_machine(&heathrow_machine);
     qemu_register_machine(&core99_machine);
@@ -3114,12 +4263,118 @@ void register_machines(void)
 #else
     qemu_register_machine(&sun4m_machine);
 #endif
+#elif defined(TARGET_ARM)
+    qemu_register_machine(&integratorcp_machine);
+#else
+#error unsupported CPU
+#endif
+}
+
+#ifdef HAS_AUDIO
+struct soundhw soundhw[] = {
+    {
+        "sb16",
+        "Creative Sound Blaster 16",
+        0,
+        1,
+        { .init_isa = SB16_init }
+    },
+
+#ifdef CONFIG_ADLIB
+    {
+        "adlib",
+#ifdef HAS_YMF262
+        "Yamaha YMF262 (OPL3)",
+#else
+        "Yamaha YM3812 (OPL2)",
+#endif
+        0,
+        1,
+        { .init_isa = Adlib_init }
+    },
+#endif
+
+#ifdef CONFIG_GUS
+    {
+        "gus",
+        "Gravis Ultrasound GF1",
+        0,
+        1,
+        { .init_isa = GUS_init }
+    },
 #endif
+
+    {
+        "es1370",
+        "ENSONIQ AudioPCI ES1370",
+        0,
+        0,
+        { .init_pci = es1370_init }
+    },
+
+    { NULL, NULL, 0, 0, { NULL } }
+};
+
+static void select_soundhw (const char *optarg)
+{
+    struct soundhw *c;
+
+    if (*optarg == '?') {
+    show_valid_cards:
+
+        printf ("Valid sound card names (comma separated):\n");
+        for (c = soundhw; c->name; ++c) {
+            printf ("%-11s %s\n", c->name, c->descr);
+        }
+        printf ("\n-soundhw all will enable all of the above\n");
+        exit (*optarg != '?');
+    }
+    else {
+        size_t l;
+        const char *p;
+        char *e;
+        int bad_card = 0;
+
+        if (!strcmp (optarg, "all")) {
+            for (c = soundhw; c->name; ++c) {
+                c->enabled = 1;
+            }
+            return;
+        }
+
+        p = optarg;
+        while (*p) {
+            e = strchr (p, ',');
+            l = !e ? strlen (p) : (size_t) (e - p);
+
+            for (c = soundhw; c->name; ++c) {
+                if (!strncmp (c->name, p, l)) {
+                    c->enabled = 1;
+                    break;
+                }
+            }
+
+            if (!c->name) {
+                if (l > 80) {
+                    fprintf (stderr,
+                             "Unknown sound card name (too big to show)\n");
+                }
+                else {
+                    fprintf (stderr, "Unknown sound card name `%.*s'\n",
+                             (int) l, p);
+                }
+                bad_card = 1;
+            }
+            p += l + (e != NULL);
+        }
+
+        if (bad_card)
+            goto show_valid_cards;
+    }
 }
+#endif
 
-#define NET_IF_TUN   0
-#define NET_IF_USER  1
-#define NET_IF_DUMMY 2
+#define MAX_NET_CLIENTS 32
 
 int main(int argc, char **argv)
 {
@@ -3128,15 +4383,14 @@ int main(int argc, char **argv)
 #endif
     int i, cdrom_index;
     int snapshot, linux_boot;
-    CPUState *env;
     const char *initrd_filename;
     const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD];
     const char *kernel_filename, *kernel_cmdline;
     DisplayState *ds = &display_state;
     int cyls, heads, secs, translation;
     int start_emulation = 1;
-    uint8_t macaddr[6];
-    int net_if_type, nb_tun_fds, tun_fds[MAX_NICS];
+    char net_clients[MAX_NET_CLIENTS][256];
+    int nb_net_clients;
     int optind;
     const char *r, *optarg;
     CharDriverState *monitor_hd;
@@ -3147,7 +4401,10 @@ int main(int argc, char **argv)
     int parallel_device_index;
     const char *loadvm = NULL;
     QEMUMachine *machine;
+    char usb_devices[MAX_VM_USB_PORTS][128];
+    int usb_devices_index;
 
+    LIST_INIT (&vm_change_state_head);
 #if !defined(CONFIG_SOFTMMU)
     /* we never want that malloc() uses mmap() */
     mallopt(M_MMAP_THRESHOLD, 4096 * 1024);
@@ -3162,7 +4419,6 @@ int main(int argc, char **argv)
     ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
     vga_ram_size = VGA_RAM_SIZE;
     bios_size = BIOS_SIZE;
-    pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT);
 #ifdef CONFIG_GDBSTUB
     use_gdbstub = 0;
     gdbstub_port = DEFAULT_GDBSTUB_PORT;
@@ -3190,16 +4446,12 @@ int main(int argc, char **argv)
         parallel_devices[i][0] = '\0';
     parallel_device_index = 0;
     
-    nb_tun_fds = 0;
-    net_if_type = -1;
-    nb_nics = 1;
+    usb_devices_index = 0;
+    
+    nb_net_clients = 0;
+
+    nb_nics = 0;
     /* default mac address of the first network interface */
-    macaddr[0] = 0x52;
-    macaddr[1] = 0x54;
-    macaddr[2] = 0x00;
-    macaddr[3] = 0x12;
-    macaddr[4] = 0x34;
-    macaddr[5] = 0x56;
     
     optind = 1;
     for(;;) {
@@ -3313,21 +4565,6 @@ int main(int argc, char **argv)
             case QEMU_OPTION_append:
                 kernel_cmdline = optarg;
                 break;
-           case QEMU_OPTION_tun_fd:
-                {
-                    const char *p;
-                    int fd;
-                    net_if_type = NET_IF_TUN;
-                    if (nb_tun_fds < MAX_NICS) {
-                        fd = strtol(optarg, (char **)&p, 0);
-                        if (*p != '\0') {
-                            fprintf(stderr, "qemu: invalid fd for network interface %d\n", nb_tun_fds);
-                            exit(1);
-                        }
-                        tun_fds[nb_tun_fds++] = fd;
-                    }
-                }
-               break;
             case QEMU_OPTION_cdrom:
                 if (cdrom_index >= 0) {
                     hd_filename[cdrom_index] = optarg;
@@ -3354,33 +4591,15 @@ int main(int argc, char **argv)
             case QEMU_OPTION_no_code_copy:
                 code_copy_enabled = 0;
                 break;
-            case QEMU_OPTION_nics:
-                nb_nics = atoi(optarg);
-                if (nb_nics < 0 || nb_nics > MAX_NICS) {
-                    fprintf(stderr, "qemu: invalid number of network interfaces\n");
+            case QEMU_OPTION_net:
+                if (nb_net_clients >= MAX_NET_CLIENTS) {
+                    fprintf(stderr, "qemu: too many network clients\n");
                     exit(1);
                 }
-                break;
-            case QEMU_OPTION_macaddr:
-                {
-                    const char *p;
-                    int i;
-                    p = optarg;
-                    for(i = 0; i < 6; i++) {
-                        macaddr[i] = strtol(p, (char **)&p, 16);
-                        if (i == 5) {
-                            if (*p != '\0') 
-                                goto macaddr_error;
-                        } else {
-                            if (*p != ':') {
-                            macaddr_error:
-                                fprintf(stderr, "qemu: invalid syntax for ethernet address\n");
-                                exit(1);
-                            }
-                            p++;
-                        }
-                    }
-                }
+                pstrcpy(net_clients[nb_net_clients],
+                        sizeof(net_clients[0]),
+                        optarg);
+                nb_net_clients++;
                 break;
 #ifdef CONFIG_SLIRP
             case QEMU_OPTION_tftp:
@@ -3391,19 +4610,19 @@ int main(int argc, char **argv)
                net_slirp_smb(optarg);
                 break;
 #endif
-            case QEMU_OPTION_user_net:
-                net_if_type = NET_IF_USER;
-                break;
             case QEMU_OPTION_redir:
                 net_slirp_redir(optarg);                
                 break;
 #endif
-            case QEMU_OPTION_dummy_net:
-                net_if_type = NET_IF_DUMMY;
+#ifdef HAS_AUDIO
+            case QEMU_OPTION_audio_help:
+                AUD_help ();
+                exit (0);
                 break;
-            case QEMU_OPTION_enable_audio:
-                audio_enabled = 1;
+            case QEMU_OPTION_soundhw:
+                select_soundhw (optarg);
                 break;
+#endif
             case QEMU_OPTION_h:
                 help();
                 break;
@@ -3433,9 +4652,6 @@ int main(int argc, char **argv)
                     cpu_set_log(mask);
                 }
                 break;
-            case QEMU_OPTION_n:
-                pstrcpy(network_script, sizeof(network_script), optarg);
-                break;
 #ifdef CONFIG_GDBSTUB
             case QEMU_OPTION_s:
                 use_gdbstub = 1;
@@ -3450,15 +4666,6 @@ int main(int argc, char **argv)
             case QEMU_OPTION_S:
                 start_emulation = 0;
                 break;
-            case QEMU_OPTION_pci:
-                pci_enabled = 1;
-                break;
-            case QEMU_OPTION_isa:
-                pci_enabled = 0;
-                break;
-            case QEMU_OPTION_prep:
-                prep_enabled = 1;
-                break;
            case QEMU_OPTION_k:
                keyboard_layout = optarg;
                break;
@@ -3545,6 +4752,27 @@ int main(int argc, char **argv)
                 kqemu_allowed = 0;
                 break;
 #endif
+            case QEMU_OPTION_usb:
+                usb_enabled = 1;
+                break;
+            case QEMU_OPTION_usbdevice:
+                usb_enabled = 1;
+                if (usb_devices_index >= MAX_VM_USB_PORTS) {
+                    fprintf(stderr, "Too many USB devices\n");
+                    exit(1);
+                }
+                pstrcpy(usb_devices[usb_devices_index],
+                        sizeof(usb_devices[usb_devices_index]),
+                        optarg);
+                usb_devices_index++;
+                break;
+            case QEMU_OPTION_smp:
+                smp_cpus = atoi(optarg);
+                if (smp_cpus < 1 || smp_cpus > MAX_CPUS) {
+                    fprintf(stderr, "Invalid number of CPUs\n");
+                    exit(1);
+                }
+                break;
             }
         }
     }
@@ -3574,48 +4802,20 @@ int main(int argc, char **argv)
 #else
     setvbuf(stdout, NULL, _IOLBF, 0);
 #endif
-
-    /* init host network redirectors */
-    if (net_if_type == -1) {
-        net_if_type = NET_IF_TUN;
-#if defined(CONFIG_SLIRP)
-        if (access(network_script, R_OK) < 0) {
-            net_if_type = NET_IF_USER;
-        }
-#endif
+    
+    /* init network clients */
+    if (nb_net_clients == 0) {
+        /* if no clients, we use a default config */
+        pstrcpy(net_clients[0], sizeof(net_clients[0]),
+                "nic");
+        pstrcpy(net_clients[1], sizeof(net_clients[0]),
+                "user");
+        nb_net_clients = 2;
     }
 
-    for(i = 0; i < nb_nics; i++) {
-        NetDriverState *nd = &nd_table[i];
-        nd->index = i;
-        /* init virtual mac address */
-        nd->macaddr[0] = macaddr[0];
-        nd->macaddr[1] = macaddr[1];
-        nd->macaddr[2] = macaddr[2];
-        nd->macaddr[3] = macaddr[3];
-        nd->macaddr[4] = macaddr[4];
-        nd->macaddr[5] = macaddr[5] + i;
-        switch(net_if_type) {
-#if defined(CONFIG_SLIRP)
-        case NET_IF_USER:
-            net_slirp_init(nd);
-            break;
-#endif
-#if !defined(_WIN32)
-        case NET_IF_TUN:
-            if (i < nb_tun_fds) {
-                net_fd_init(nd, tun_fds[i]);
-            } else {
-                if (net_tun_init(nd) < 0)
-                    net_dummy_init(nd);
-            }
-            break;
-#endif
-        case NET_IF_DUMMY:
-        default:
-            net_dummy_init(nd);
-            break;
-        }
+    for(i = 0;i < nb_net_clients; i++) {
+        if (net_client_init(net_clients[i]) < 0)
+            exit(1);
     }
 
     /* init the memory */
@@ -3710,15 +4910,19 @@ int main(int argc, char **argv)
         }
     }
 
-    /* init CPU state */
-    env = cpu_init();
-    global_env = env;
-    cpu_single_env = env;
+    /* init USB devices */
+    if (usb_enabled) {
+        vm_usb_hub = usb_hub_init(vm_usb_ports, MAX_VM_USB_PORTS);
+        for(i = 0; i < usb_devices_index; i++) {
+            if (usb_device_add(usb_devices[i]) < 0) {
+                fprintf(stderr, "Warning: could not add USB device %s\n",
+                        usb_devices[i]);
+            }
+        }
+    }
 
-    register_savevm("timer", 0, 1, timer_save, timer_load, env);
-    register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
+    register_savevm("timer", 0, 1, timer_save, timer_load, NULL);
     register_savevm("ram", 0, 1, ram_save, ram_load, NULL);
-    qemu_register_reset(main_cpu_reset, global_env);
 
     init_ioports();
     cpu_calibrate_ticks();
index 31d05b6..7a10728 100644 (file)
--- a/qemu/vl.h
+++ b/qemu/vl.h
@@ -97,8 +97,14 @@ int strstart(const char *str, const char *val, const char **ptr);
 
 extern int vm_running;
 
+typedef struct vm_change_state_entry VMChangeStateEntry;
+typedef void VMChangeStateHandler(void *opaque, int running);
 typedef void VMStopHandler(void *opaque, int reason);
 
+VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
+                                                     void *opaque);
+void qemu_del_vm_change_state_handler(VMChangeStateEntry *e);
+
 int qemu_add_vm_stop_handler(VMStopHandler *cb, void *opaque);
 void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque);
 
@@ -120,10 +126,6 @@ void qemu_system_powerdown(void);
 
 void main_loop_wait(int timeout);
 
-extern int audio_enabled;
-extern int sb16_enabled;
-extern int adlib_enabled;
-extern int gus_enabled;
 extern int ram_size;
 extern int bios_size;
 extern int rtc_utc;
@@ -134,6 +136,8 @@ extern int graphic_depth;
 extern const char *keyboard_layout;
 extern int kqemu_allowed;
 extern int win2k_install_hack;
+extern int usb_enabled;
+extern int smp_cpus;
 
 /* XXX: make it dynamic */
 #if defined (TARGET_PPC)
@@ -188,16 +192,41 @@ void kbd_put_keysym(int keysym);
 
 typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
 typedef int IOCanRWHandler(void *opaque);
+typedef void IOHandler(void *opaque);
 
-int qemu_add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, 
-                             IOReadHandler *fd_read, void *opaque);
-void qemu_del_fd_read_handler(int fd);
+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_write,
+                        void *opaque);
 
 /* character device */
 
 #define CHR_EVENT_BREAK 0 /* serial break char */
 #define CHR_EVENT_FOCUS 1 /* focus to this terminal (modal input needed) */
 
+
+
+#define CHR_IOCTL_SERIAL_SET_PARAMS   1
+typedef struct {
+    int speed;
+    int parity;
+    int data_bits;
+    int stop_bits;
+} QEMUSerialSetParams;
+
+#define CHR_IOCTL_SERIAL_SET_BREAK    2
+
+#define CHR_IOCTL_PP_READ_DATA        3
+#define CHR_IOCTL_PP_WRITE_DATA       4
+#define CHR_IOCTL_PP_READ_CONTROL     5
+#define CHR_IOCTL_PP_WRITE_CONTROL    6
+#define CHR_IOCTL_PP_READ_STATUS      7
+
 typedef void IOEventHandler(void *opaque, int event);
 
 typedef struct CharDriverState {
@@ -205,6 +234,7 @@ typedef struct CharDriverState {
     void (*chr_add_read_handler)(struct CharDriverState *s, 
                                  IOCanRWHandler *fd_can_read, 
                                  IOReadHandler *fd_read, void *opaque);
+    int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg);
     IOEventHandler *chr_event;
     void (*chr_send_event)(struct CharDriverState *chr, int event);
     void *opaque;
@@ -217,7 +247,8 @@ void qemu_chr_add_read_handler(CharDriverState *s,
                                IOCanRWHandler *fd_can_read, 
                                IOReadHandler *fd_read, void *opaque);
 void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event);
-                               
+int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg);
+
 /* consoles */
 
 typedef struct DisplayState DisplayState;
@@ -242,30 +273,42 @@ extern CharDriverState *serial_hds[MAX_SERIAL_PORTS];
 
 extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
 
-/* network redirectors support */
+/* VLANs support */
+
+typedef struct VLANClientState VLANClientState;
+
+struct VLANClientState {
+    IOReadHandler *fd_read;
+    void *opaque;
+    struct VLANClientState *next;
+    struct VLANState *vlan;
+    char info_str[256];
+};
+
+typedef struct VLANState {
+    int id;
+    VLANClientState *first_client;
+    struct VLANState *next;
+} VLANState;
+
+VLANState *qemu_find_vlan(int id);
+VLANClientState *qemu_new_vlan_client(VLANState *vlan,
+                                      IOReadHandler *fd_read, void *opaque);
+void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size);
+
+void do_info_network(void);
+
+/* NIC info */
 
 #define MAX_NICS 8
 
-typedef struct NetDriverState {
-    int index; /* index number in QEMU */
+typedef struct NICInfo {
     uint8_t macaddr[6];
-    char ifname[16];
-    void (*send_packet)(struct NetDriverState *nd, 
-                        const uint8_t *buf, int size);
-    void (*add_read_packet)(struct NetDriverState *nd, 
-                            IOCanRWHandler *fd_can_read, 
-                            IOReadHandler *fd_read, void *opaque);
-    /* tun specific data */
-    int fd;
-    /* slirp specific data */
-} NetDriverState;
+    VLANState *vlan;
+} NICInfo;
 
 extern int nb_nics;
-extern NetDriverState nd_table[MAX_NICS];
-
-void qemu_send_packet(NetDriverState *nd, const uint8_t *buf, int size);
-void qemu_add_read_packet(NetDriverState *nd, IOCanRWHandler *fd_can_read, 
-                          IOReadHandler *fd_read, void *opaque);
+extern NICInfo nd_table[MAX_NICS];
 
 /* timers */
 
@@ -382,6 +425,9 @@ int register_savevm(const char *idstr,
 void qemu_get_timer(QEMUFile *f, QEMUTimer *ts);
 void qemu_put_timer(QEMUFile *f, QEMUTimer *ts);
 
+void cpu_save(QEMUFile *f, void *opaque);
+int cpu_load(QEMUFile *f, void *opaque, int version_id);
+
 /* block.c */
 typedef struct BlockDriverState BlockDriverState;
 typedef struct BlockDriver BlockDriver;
@@ -486,8 +532,6 @@ void isa_unassign_ioport(int start, int length);
 
 /* PCI bus */
 
-extern int pci_enabled;
-
 extern target_phys_addr_t pci_mem_base;
 
 typedef struct PCIBus PCIBus;
@@ -564,13 +608,29 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base);
 /* 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);
+openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
+                         CPUState **envp);
 
 /* 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);
 
+#ifdef HAS_AUDIO
+struct soundhw {
+    const char *name;
+    const char *descr;
+    int enabled;
+    int isa;
+    union {
+        int (*init_isa) (AudioState *s);
+        int (*init_pci) (PCIBus *bus, AudioState *s);
+    } init;
+};
+
+extern struct soundhw soundhw[];
+#endif
+
 /* vga.c */
 
 #define VGA_RAM_SIZE (4096 * 1024)
@@ -628,14 +688,17 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table);
 int pmac_ide_init (BlockDriverState **hd_table,
                    SetIRQFunc *set_irq, void *irq_opaque, int irq);
 
+/* es1370.c */
+int es1370_init (PCIBus *bus, AudioState *s);
+
 /* sb16.c */
-void SB16_init (void);
+int SB16_init (AudioState *s);
 
 /* adlib.c */
-void Adlib_init (void);
+int Adlib_init (AudioState *s);
 
 /* gus.c */
-void GUS_init (void);
+int GUS_init (AudioState *s);
 
 /* dma.c */
 typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size);
@@ -663,8 +726,8 @@ int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num);
 
 /* ne2000.c */
 
-void isa_ne2000_init(int base, int irq, NetDriverState *nd);
-void pci_ne2000_init(PCIBus *bus, NetDriverState *nd);
+void isa_ne2000_init(int base, int irq, NICInfo *nd);
+void pci_ne2000_init(PCIBus *bus, NICInfo *nd);
 
 /* pckbd.c */
 
@@ -681,7 +744,11 @@ void rtc_set_date(RTCState *s, const struct tm *tm);
 /* serial.c */
 
 typedef struct SerialState SerialState;
-SerialState *serial_init(int base, int irq, CharDriverState *chr);
+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);
 
 /* parallel.c */
 
@@ -724,6 +791,10 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time);
 
 /* pc.c */
 extern QEMUMachine pc_machine;
+extern QEMUMachine isapc_machine;
+
+void ioport_set_a20(int enable);
+int ioport_get_a20(void);
 
 /* ppc.c */
 extern QEMUMachine prep_machine;
@@ -740,19 +811,19 @@ void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val);
 
 extern CPUWriteMemoryFunc *PPC_io_write[];
 extern CPUReadMemoryFunc *PPC_io_read[];
-extern int prep_enabled;
 void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val);
 
 /* sun4m.c */
 extern QEMUMachine sun4m_machine;
 uint32_t iommu_translate(uint32_t addr);
+void pic_set_irq_cpu(int irq, int level, unsigned int cpu);
 
 /* iommu.c */
 void *iommu_init(uint32_t addr);
 uint32_t iommu_translate_local(void *opaque, uint32_t addr);
 
 /* lance.c */
-void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr);
+void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr);
 
 /* tcx.c */
 void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
@@ -763,16 +834,18 @@ void tcx_screen_dump(void *opaque, const char *filename);
 
 /* slavio_intctl.c */
 void *slavio_intctl_init();
+void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env);
 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);
 
 /* magic-load.c */
 int load_elf(const char *filename, uint8_t *addr);
 int load_aout(const char *filename, uint8_t *addr);
 
 /* slavio_timer.c */
-void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2);
+void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu);
 
 /* slavio_serial.c */
 SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2);
@@ -855,6 +928,33 @@ void adb_mouse_init(ADBBusState *bus);
 extern ADBBusState adb_bus;
 int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq);
 
+#include "hw/usb.h"
+
+/* usb ports of the VM */
+
+#define MAX_VM_USB_PORTS 8
+
+extern USBPort *vm_usb_ports[MAX_VM_USB_PORTS];
+extern USBDevice *vm_usb_hub;
+
+void do_usb_add(const char *devname);
+void do_usb_del(const char *devname);
+void usb_info(void);
+
+/* integratorcp.c */
+extern QEMUMachine integratorcp_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);
+void ps2_write_mouse(void *, int val);
+void ps2_write_keyboard(void *, int val);
+uint32_t ps2_read_data(void *);
+void ps2_queue(void *, int b);
+
+/* smc91c111.c */
+void smc91c111_init(NICInfo *, uint32_t, void *, int);
+
 #endif /* defined(QEMU_TOOL) */
 
 /* monitor.c */