Lots of changes
authorMichael Meissner <gnu@the-meissners.org>
Wed, 1 Nov 1995 19:32:38 +0000 (19:32 +0000)
committerMichael Meissner <gnu@the-meissners.org>
Wed, 1 Nov 1995 19:32:38 +0000 (19:32 +0000)
14 files changed:
sim/ppc/.Sanitize
sim/ppc/ChangeLog
sim/ppc/Makefile.in
sim/ppc/config.hdr [new file with mode: 0755]
sim/ppc/config.make [new file with mode: 0755]
sim/ppc/configure
sim/ppc/configure.in
sim/ppc/debug.h [new file with mode: 0644]
sim/ppc/emul_netbsd.c [new file with mode: 0644]
sim/ppc/filter_filename.c [new file with mode: 0644]
sim/ppc/filter_filename.h [new file with mode: 0644]
sim/ppc/igen.c [new file with mode: 0644]
sim/ppc/misc.h [new file with mode: 0644]
sim/ppc/ppc-instructions [new file with mode: 0644]

index efa34bd..195a020 100644 (file)
@@ -33,6 +33,8 @@ bits.c
 bits.h
 build-psim
 config.in
+config.make
+config.hdr
 configure
 configure.in
 core.c
@@ -55,6 +57,8 @@ emul_netbsd.c
 emul_netbsd.h
 events.c
 events.h
+filter_filename.c
+filter_filename.h
 idecode_branch.h
 idecode_expression.h
 idecode_fields.h
index feaef07..66b2465 100644 (file)
@@ -1,3 +1,53 @@
+Wed Nov  1 10:49:48 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
+
+       * emul_netbsd.c (do_exit): Print arguments and close parenthesis
+       if tracing, since exit doesn't go through emul_exit_call.
+       (do_read): Print arguments if tracing.
+       (do_write): Ditto.
+       (do_open): Ditto.
+       (do_break): Ditto.
+       (do_kill): Ditto.
+       (do_dup): Ditto.
+       (do_sigprocmask): Replace trace with printing arguments if
+       tracing.
+       (do_ioctl): Print arguments if tracing.
+       (do_umask): Ditto.
+       (do_dup2): Ditto.
+       (do_fcntl): Ditto.
+       (do_gettimeofday): Ditto.
+       (do_getrusage): Ditto.
+       (do_fstatfs): Ditto.
+
+       * filter_filename.c: New file to provide filter_filename to strip
+       the directory prefix from a file.
+       * filter_filename.h: New include file to declare filter_filename.
+
+       * debug.h: Include filter_filename.h.
+       (TRACE,DTRACE,ERROR): Use filter_filename on __FILE__.
+
+       * misc.h: Include filter_filename.h.
+       (ASSERT): Use filter_filename on __FILE__.
+
+       * igen.c (lf_print_my_prefix): Use filter_filename on the filename
+       argument.
+
+       * Makefile.in: Add filter_filename support.
+
+       * ppc-instructions (dcbi, icbi): Make these NOPs rather than
+       invalid instructions.
+
+       * configure.in: Add support for more --enable-sim-* switches.
+       Use config.make and config.hdr to write to Makefile and config.h
+       respectively.  Don't rewrite Makefile, just append to it.
+       * configure: Regenerate.
+       * config.{make,hdr}: New shell scripts.
+       
+       * Makefile.in: Remove all variables set by configure.in.
+       (psim.o): Depend on $(BUILT_SRC) also.
+
+       * emul_netbsd.c (do_gettimeofday,do_getrusage): When comparing an
+       integer, use 0, not NULL.
+
 Tue Oct 31 15:20:04 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
 
        * configure.in: Add support for --enable-sim-inline,
@@ -6,19 +56,19 @@ Tue Oct 31 15:20:04 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
        and --enable-sim-endian switch to control various Makefile
        variables.
        * configure: Regenerate from configure.in.
-       * Makefile: Add various Make variables that the various switches
-       alter.
+       * Makefile.in: Add various Make variables that the various
+       switches alter.
 
        * std-config.h (DEFAULT_INLINE): Don't set this to 2 if using GCC
        and optimizing by default.
 
-Fri Oct 27 19:26:27 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Fri Oct 27 19:26:27 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * bits.h (ROTL32, ROTL64): Were functions, made them macros, now
        make them functions again.  Appears 2.6.3 is confused by just a
        macro.
 
-Thu Oct 26 18:31:58 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Thu Oct 26 18:31:58 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * ppc-endian.c (SWAP_8): Fix 8 byte swap!
 
@@ -30,18 +80,18 @@ Thu Oct 26 18:31:58 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
        trace_semantics is now different to trace_idecode, the former
        checks the cache.
        
-Tue Oct 24 21:54:13 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Tue Oct 24 21:54:13 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * ppc-instructions (mtsrin): Missing instruction
        * ppc-instructions (mfsrin): Missing instruction
        * ppc-instructions (eieio): Missing instruction
 
-Tue Oct 24 20:55:29 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Tue Oct 24 20:55:29 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * build-psim: New shell script - see internals for usage,
        simplifies the process of building custom simulators.
 
-Mon Oct 23 23:48:59 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Mon Oct 23 23:48:59 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * std-config.h (SEMANTICS_INLINE): Tidy up notes on each of the
         INLINE macros.  Make SEMANTICS_INLINE == 1 if DEFAULT_INLINE == 2.
@@ -55,7 +105,7 @@ Mon Oct 23 23:48:59 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
        * FIXME: devices.c/emul_netbsd.c would benefit (slightly) from
        the inclusion of device_tree.c/emul_generic.c.
 
-Mon Oct 23 00:31:50 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Mon Oct 23 00:31:50 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * os_emul.[hc], emul_generic.[hc], emul_netbsd.[hc]: replace
         system.[hc].  Start of suport for multiple emulations and
@@ -64,7 +114,7 @@ Mon Oct 23 00:31:50 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
        * emul_generic.[hc]: Start of code to implement proper system call
        tracing (from spy).
 
-Sun Oct 22 21:33:51 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Sun Oct 22 21:33:51 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * cpu.h, cpu.c (cpu_init): New function, zero the registers before
         the processor is started. Fixes problem of registers being
@@ -84,7 +134,7 @@ Sun Oct 22 21:33:51 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
        performing an isync when the instruction stream doesn't contain
        one.
 
-Sun Oct 22 19:27:48 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Sun Oct 22 19:27:48 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * mon.h (new), mon.c (new), std-config.h (WITH_MON): Performance
         monitoring module. Counts both instructions issued and
@@ -104,20 +154,20 @@ Sun Oct 22 19:27:48 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
         cpu_increment_number_of_insns() and cpu_get_number_of_insns()
         replaced by copied code in mon.[hc].
 
-Sun Oct 22 18:42:45 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Sun Oct 22 18:42:45 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * sim_calls.c, main.c, psim.c (psim_create): always create
         `WITH_SMP' cpus.  The actual number of CPU's active in a
         simulation run is taken from the device node: /init/smp (an
         integer). WITH_SMP changed to 2 (remember to put it back to 0).
 
-Fri Oct 20 17:26:54 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Fri Oct 20 17:26:54 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * system.c: More system call emulation.  If code appears NetBSD
        specific, make conditional to being compiled on a NetBSD system
        (sigh).
 
-Wed Oct 18 23:02:20 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Wed Oct 18 23:02:20 1995  Andrew Cagney  <cagney@highland.com.au>
        
        * Makefile.in, gen.c(delete), igen.c(new), dgen.c(new),
        lf.[ch](new), table.[ch](new): Split into two generators - igen
@@ -161,7 +211,7 @@ Wed Oct 18 23:02:20 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
        * ppc-instructions (64bit Floating Convert from Integer
        Doubleword): Correct call to Round_Float().
 
-Mon Oct 16 00:31:20 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Mon Oct 16 00:31:20 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * basics.h: #include "sim_callbacks.h" earlier so that its
        prototypes are declared in all other header files.
@@ -177,7 +227,7 @@ Mon Oct 16 00:31:20 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
        Add size of buffer argument to functions writing a string into a
        buffer.  Check for buffer overflow.
        
-Sun Oct 15 22:16:11 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Sun Oct 15 22:16:11 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * devices.h, devices.c, debug.h, debug.c: add macro's for tracing
         of each device.  Make parameter names consistent so macros work.
@@ -191,7 +241,7 @@ Sun Oct 15 22:16:11 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
        * core.c: add tracing of core-device, adjust parameter names in
        core functions to be consistent with those in devices*.
 
-Sun Oct 15 20:33:20 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Sun Oct 15 20:33:20 1995  Andrew Cagney  <cagney@highland.com.au>
 
         * debug.h, debug.c (trace_option): New function. Parses the trace
         option, updating the trace array.
@@ -301,7 +351,7 @@ Thu Oct 12 11:35:53 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
        ({CORE,VM,CPU,EVENTS,REGISTERS,INTERRUPTS}_INLINE): Ditto.
        ({SPREG,IDECODE}_INLINE): Ditto.        
        
-Wed Oct 11 17:13:15 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Wed Oct 11 17:13:15 1995  Andrew Cagney  <cagney@highland.com.au>
 
         * ppc-instructions: Initial cut of floating point suport added.
        Of note include - use of host IEEE floating point instructions,
@@ -318,7 +368,7 @@ Wed Oct 11 17:13:15 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
        * Makefile.in et.al (sorry): tweek to use new core, core_map and
        core.h.
        
-Wed Oct 11 12:10:26 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Wed Oct 11 12:10:26 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * sim_calls.c, main.c: Add -g (trace_gdb) option, add tracing to
        most of the other functions in sim_calls.c.
@@ -329,7 +379,7 @@ Wed Oct 11 12:10:26 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
 
        * vm.c, vm_n.h, Makefile.in: ditto
        
-Tue Oct 10 15:42:59 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Tue Oct 10 15:42:59 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * devices.h, devices.c, memory_map.h, memory_map.c: Changed
        callback interface so that there is a read/write buffer but no
@@ -341,12 +391,12 @@ Tue Oct 10 15:42:59 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
        eliminate transfer_mode (raw or cooked) parameter from read/write
        buffer.
        
-Fri Oct  6 20:23:56 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Fri Oct  6 20:23:56 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * ppc-instructions (fmul, fmuls): correct instruction format - had
        FRB instead of FRC.
 
-Wed Oct  4 17:31:12 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Wed Oct  4 17:31:12 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * psim.c, device_tree.h, device_tree.c, devices.c (printd_*,
        scand_*): new functions to parse/print fields in device names
@@ -360,7 +410,7 @@ Wed Oct  4 17:31:12 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
        variable number of arguments.  This gives greater flexability and
        greater chance of bugs.
 
-Tue Oct  3 22:01:56 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Tue Oct  3 22:01:56 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * main.c (printf_filtered, error): Missing va_end() to close off
         variable argument use.
@@ -483,7 +533,7 @@ Fri Sep  8 09:51:03 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
        * basics.h (sysdep.h): Don't include it.
        * Makefile.in (BASICS_H): Remove sysdep.h.
 
-Wed Sep  6 13:25:42 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Wed Sep  6 13:25:42 1995  Andrew Cagney  <cagney@highland.com.au>
  
        * core.c (core_add_data): First growth of bss was being put at
         wrong address (0) instead of &end.
@@ -491,7 +541,7 @@ Wed Sep  6 13:25:42 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
        * core.c (core_add_stack, core_add_data): Was not handling case
         where bss/stack is grown across the current end-of-{bss,stack}.
 
-Wed Sep  6 00:46:10 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Wed Sep  6 00:46:10 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * system.c (system_call): Fix SYS_break - was aligning bss to a
         page boundary instead of just an 8 byte one; On first call sbrk(0)
@@ -537,7 +587,7 @@ Tue Aug 22 09:31:18 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
        * configure.in: Clone from other simulator targets.
        * configure: Generate via autoconf from configure.in.
 
-Sat Aug 19 09:05:32 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Sat Aug 19 09:05:32 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * ppc-instructions: fix srawi (was geting XER[CA] real wrong).
 
@@ -548,14 +598,14 @@ Sat Aug 19 09:05:32 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
 
        * main.c (main): really stupid. Wasn't exiting with correct status
 
-Fri Aug 18 00:38:01 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Fri Aug 18 00:38:01 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * system.c (system_call): add system calls kill(2) and getpid(2).
 
        * main.c (main): Check/return exit status when simulation
         finishes.
 
-Thu Aug 17 14:29:18 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Thu Aug 17 14:29:18 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * device_tree.c (create_option_device_node): Alignment rules (at
        least for the moment) now are for strict alignment only for LE OEA
@@ -563,7 +613,7 @@ Thu Aug 17 14:29:18 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
 
        * system.c (system_call) SYS_exit: Wasn't exiting with correct status.
 
-Thu Aug 17 01:16:38 1995  Andrew Cagney  <cagney@cagney@highland.com.au>
+Thu Aug 17 01:16:38 1995  Andrew Cagney  <cagney@highland.com.au>
 
        * vm.c (DEFINE_VM_DATA_MAP_WRITE_N): For miss aligned transfer
         forgot to return.
index d92ca56..f2c7625 100644 (file)
@@ -68,6 +68,7 @@ RANLIB = @RANLIB@
 
 HDEFINES = @HDEFINES@
 TDEFINES =
+IGEN_FLAGS = $(IGEN_DUPLICATE) $(IGEN_FILTER)
 
 .NOEXPORT:
 MAKEOVERRIDES=
@@ -77,24 +78,15 @@ BFD_INCLUDES        = -I../../bfd -I$(srcdir)/../../bfd
 GDB_INCLUDES   = -I../../gdb -I$(srcdir)/../../gdb  -I$(srcdir)/../../gdb/config -I$(srcdir)/../../mmalloc
 INCLUDES       = -I. -I$(srcdir) $(LIB_INCLUDES) $(BFD_INCLUDES) $(GDB_INCLUDES)
 
-CONFIG_FILE    = std-config.h
-
-# See inline.h for appropriate flags to set
-INLINE_CFLAGS  =                       # -g0 -DDEFAULT_INLINE=2
-IGEN_FLAGS = -f 64                     # -f 64 -e
-IGEN_OPCODE_RULES = ppc-opcode-simple  # ppc-opcode-complex
-DGEN_FLAGS =                           # # -s
-
-
 LIBIBERTY_LIB  = ../../libiberty/libiberty.a
 BFD_LIB                = ../../bfd/libbfd.a
 
-TARGETLIB = libsim.a
+TARGETLIB      = libsim.a
 
 all:   run $(TARGETLIB) $(GDB_OBJ)
 
 .c.o:
-       $(CC) -c $(CFLAGS) $(INLINE_CFLAGS) $(HDEFINES) $(TDEFINES) $(INCLUDES) $<
+       $(CC) -c $(CFLAGS) $(INLINE_CFLAGS) $(SIM_CFLAGS) $(HDEFINES) $(TDEFINES) $(INCLUDES) $<
 
 
 
@@ -104,6 +96,7 @@ BASICS_H = \
        words.h \
        ppc-endian.h \
        debug.h \
+       filter_filename.h \
        bits.h \
        sim_callbacks.h
 
@@ -183,6 +176,7 @@ MAIN_SRC = \
 #       first
 LIB_OBJ = \
        debug.o \
+       filter_filename.o \
        bits.o \
        ppc-endian.o \
        os_emul.o \
@@ -221,11 +215,12 @@ $(TARGETLIB): tmp-igen tmp-dgen $(LIB_OBJ) $(GDB_OBJ)
 
 # Given that inlines are turned on now, rebuild psim whenever
 # anything changes.
-psim.o: psim.c psim.h $(CPU_H) $(IDECODE_H) $(INLINE) $(LIB_SRC)
+psim.o: psim.c psim.h $(CPU_H) $(IDECODE_H) $(INLINE) $(LIB_SRC) $(BUILT_SRC)
 
 bits.o: bits.c $(BASICS_H)
 
 debug.o: debug.c $(BASICS_H)
+filter_filename.o: filter_filename.c $(BASICS_H)
 
 ppc-endian.o: ppc-endian.c ppc-endian.h \
        config.h ppc-config.h words.h sim_callbacks.h
@@ -314,16 +309,16 @@ tmp-igen: igen ppc-instructions $(IGEN_OPCODE_RULES) ppc-cache-rules $(srcdir)/.
 # itable.h itable.c icache.h idecode.h idecode.c semantics.h semantics.c: tmp-igen
 # spreg.h spreg.c: tmp-dgen
 
-dgen: dgen.o table.o lf.o misc.o
-       $(CC_FOR_BUILD) $(CFLAGS) $(LDFLAGS) -o dgen dgen.o table.o lf.o misc.o $(LIBIBERTY_LIB) $(LIBS)
+dgen: dgen.o table.o lf.o misc.o filter_filename.o
+       $(CC_FOR_BUILD) $(CFLAGS) $(LDFLAGS) -o dgen dgen.o table.o lf.o misc.o filter_filename.o $(LIBIBERTY_LIB) $(LIBS)
 
-igen: igen.o table.o lf.o misc.o
-       $(CC_FOR_BUILD) $(CFLAGS) $(LDFLAGS) -o igen igen.o table.o lf.o misc.o $(LIBIBERTY_LIB) $(LIBS)
+igen: igen.o table.o lf.o misc.o filter_filename.o
+       $(CC_FOR_BUILD) $(CFLAGS) $(LDFLAGS) -o igen igen.o table.o lf.o misc.o filter_filename.o $(LIBIBERTY_LIB) $(LIBS)
 
-table.o: misc.h lf.h table.h
-lf.o: misc.h lf.h
-dgen.o igen.o: misc.h lf.h table.h
-misc.o: misc.h
+table.o: misc.h filter_filename.h lf.h table.h
+lf.o: misc.h filter_filename.h lf.h
+dgen.o igen.o: misc.h filter_filename.h lf.h table.h
+misc.o: misc.h filter_filename.h
 # With out this #, make thinks that misc.o doesn't have a rule
 
 tags etags: TAGS
@@ -344,9 +339,11 @@ config.h: stamp-h ; @true
 stamp-h: config.in config.status
        CONFIG_FILES= CONFIG_HEADERS=config.h:config.in $(SHELL) ./config.status
 
-config.status: configure
+config.status: configure config.make config.hdr
        $(SHELL) ./config.status --recheck
 
 install:
        $(INSTALL_XFORM) run $(bindir)/run
 
+
+# Make variables generated automatically by configure follow this
diff --git a/sim/ppc/config.hdr b/sim/ppc/config.hdr
new file mode 100755 (executable)
index 0000000..98fa86b
--- /dev/null
@@ -0,0 +1,52 @@
+#! /bin/sh
+
+# Helper script to turn --enable-sim-xxx switches into defines
+
+# Arg 1 -- header name
+# Arg 2 -- define name
+# Arg 3 -- --enable-sim switch spelling
+# Arg 4 -- --enable-sim switch value
+# the remaining switches are paired, with the first being the value to test arg 4 against
+# and the second is the value to put in the define if it matches
+
+hdr="$1"
+shift
+
+define="$1"
+shift
+
+switch="$1"
+shift
+
+value="$1"
+shift
+
+while test $# -gt 1; do
+       test_value="$1"
+       shift
+
+       set_value="$1"
+       shift
+
+       if test x"$value" = x"$test_value" -o x"$test_value" = x"*"; then
+               echo "Defining $define=$set_value"
+               (echo ""
+                if test x"$value" = x""; then
+                        echo "/* no $switch */"
+                elif test x"$value" = x"yes"; then
+                        echo "/* $switch */"
+                else
+                        echo "/* $switch=$value */"
+                fi
+
+                echo "#ifndef $define"
+                echo "#define $define $set_value"
+                echo "#endif") >> $hdr
+               exit 0;
+       fi
+done
+
+if test x"$value" != x"" -a x"$value" != x"no"; then
+       echo "$switch=$value is not supported" 1>&2
+       exit 1
+fi
diff --git a/sim/ppc/config.make b/sim/ppc/config.make
new file mode 100755 (executable)
index 0000000..388fe36
--- /dev/null
@@ -0,0 +1,53 @@
+#! /bin/sh
+
+# Helper script to turn --enable-sim-xxx switches into make variables
+
+# Arg 1 -- header name
+# Arg 2 -- define name
+# Arg 3 -- --enable-sim switch spelling
+# Arg 4 -- --enable-sim switch value
+# the remaining switches are paired, with the first being the value to test arg 4 against
+# and the second is the value to put in the define if it matches
+
+make="$1"
+shift
+
+makevar="$1"
+shift
+
+switch="$1"
+shift
+
+value="$1"
+shift
+
+while test $# -gt 1; do
+       test_value="$1"
+       shift
+
+       set_value="$1"
+       shift
+
+       if test x"$value" = x"$test_value" -o x"$test_value" = x"*"; then
+               echo "Setting $makevar=$set_value"
+               (echo "";
+                if test x"$value" = x""; then
+                        echo "# no $switch";
+                elif test x"$value" = x"yes"; then
+                        echo "# $switch";
+                else
+                        echo "# $switch=$value";
+                fi
+                if test x"$set_value" = x""; then
+                        echo "$makevar ="
+                else
+                        echo "$makevar = $set_value"
+                fi) >> $make
+               exit 0;
+       fi
+done
+
+if test x"$value" != x"" -a x"$value" != x"no"; then
+       echo "$switch=$value is not supported" 1>&2
+       exit 1
+fi
index ebf3a51..3b5059a 100755 (executable)
@@ -1040,13 +1040,41 @@ rm -fr confdefs* $ac_clean_files
 test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
 
 
+if test x"$enable_sim_cflags" != x"" -a x"$enable_sim_cflags" != x"no"; then
+  if test "$enable_sim_cflags" = "yes"; then
+    enable_sim_cflags="-fomit-frame-pointer,-O2"
+  fi
+  echo "Setting SIM_CFLAGS=$enable_sim_cflags" | sed -e "s/,/ /g" 1>&6
+  (echo; echo "# --enable-sim-cflags=$enable_sim_cflags";
+   echo "SIM_CFLAGS = $enable_sim_cflags" | sed -e "s/,/ /g") >> Makefile
+else
+  echo "Setting SIM_CFLAGS=" 1>&6
+  (echo; echo "# no --enable-sim-cflags"; echo "SIM_CFLAGS =") >> Makefile
+fi
+
+$srcdir/config.make Makefile CONFIG_FILE --enable-sim-config "$enable_sim_config" \
+  "" "std-config.h" "no" "std-config.h" "yes" "std-config.h" "*" "$enable_sim_config" 1>&6
+
+$srcdir/config.make Makefile IGEN_OPCODE_RULES --enable-sim-opcode "$enable_sim_opcode" \
+  "" "ppc-opcode-simple" "no" "ppc-opcode-simple" "yes" "ppc-opcode-simple" \
+  "complex" "ppc-opcode-complex" "simple" "ppc-opcode-simple" 1>&6
+
+$srcdir/config.make Makefile DGEN_FLAGS --enable-sim-switch "$enable_sim_switch" \
+  "" "" "no" "" "yes" "-s" 1>&6
+
+$srcdir/config.make Makefile IGEN_DUPLICATE --enable-sim-duplicate "$enable_sim_duplicate" \
+  "" "" "no" "" "yes" "-e" 1>&6
+
+$srcdir/config.make Makefile IGEN_FILTER --enable-sim-filter "$enable_sim_filter" \
+  "" "-f 64" "no" "" "yes" "-f 64" "*" "$enable_sim_filter" 1>&6
+
+flags=""
 if test x"$enable_sim_inline" != x""; then
-  flags=""
   case "$enable_sim_inline" in
     no)                flags="";;
-    0)         flags="-DDEFAULT_INLINE=0";;
-    yes | 2)   flags="-DDEFAULT_INLINE=2";;
-    1)         flags="-DDEFAULT_INLINE=1";;
+    0)         flags=" -DDEFAULT_INLINE=0";;
+    yes | 2)   flags=" -DDEFAULT_INLINE=2";;
+    1)         flags=" -DDEFAULT_INLINE=1";;
     *) for x in `echo "$enable_sim_inline" | sed -e "s/,/ /g"`; do
         case "$x" in
           *_INLINE=*)  flags="$flags -D$x";;
@@ -1056,87 +1084,68 @@ if test x"$enable_sim_inline" != x""; then
         esac
        done;;
   esac
-  if test x"$flags" != x""; then
-    mv Makefile Makefile.tem
-    echo "Setting INLINE_CFLAGS=$flags" 1>&6
-    sed -e "s/^INLINE_CFLAGS.*=.*\$/INLINE_CFLAGS =$flags/" \
-      < Makefile.tem > Makefile
-    rm -f Makefile.tem
-  fi
 fi
-
-if test x"$enable_sim_bswap" != x"" -a x"$enable_sim_bswap" != x"no"; then
-  mv Makefile Makefile.tem
-  echo "Setting BSWAP_CFLAGS=-DWITH_BSWAP=1" 1>&6
-  sed -e "s/^BSWAP_CFLAGS.*=.*\$/BSWAP_CFLAGS = -DWITH_BSWAP=1/" \
-    < Makefile.tem > Makefile
-  rm -f Makefile.tem
+if test x"$flags" != x""; then
+  echo "Setting INLINE_CFLAGS=$flags" 1>&6
+  (echo; echo "# --enable-sim-inline=$enable_sim_inline"; echo "INLINE_CFLAGS =$flags") >> Makefile
+else
+  echo "Setting INLINE_CFLAGS=" 1>&6
+  (echo; echo "# no --enable-sim-inline"; echo "INLINE_CFLAGS =") >> Makefile 
 fi
 
-if test x"$enable_sim_cflags" != x"" -a x"$enable_sim_cflags" != x"no"; then
-  if test "$enable_sim_cflags" = "yes"; then
-    enable_sim_cflags="-fomit-frame-pointer,-O2"
-  fi
-  mv Makefile Makefile.tem
-  echo "Setting SIM_CFLAGS=$enable_sim_cflags"
-  sed -e "s/^SIM_CFLAGS.*=.*\$/SIM_CFLAGS = $enable_sim_cflags/" -e "s/,/ /g"\
-    < Makefile.tem > Makefile
-  rm -f Makefile.tem
-fi
+$srcdir/config.hdr config.h WITH_BSWAP --enable-sim-bswap "$enable_sim_bswap" "yes" 1
 
-if test x"$enable_sim_complex" != x"" -a x"$enable_sim_complex" != x"no"; then
-  mv Makefile Makefile.tem
-  echo "Setting IGEN_OPCODE_RULES=ppc-opcode-complex" 1>&6
-  sed -e "s/^IGEN_OPCODE_RULES.*=.*\$/IGEN_OPCODE_RULES = ppc-opcode-complex/" \
-    < Makefile.tem > Makefile
-  rm -f Makefile.tem
-fi
+case "$target" in
+  *powerpc-*) endian="BIG_ENDIAN";;
+  *powerpcle-*) endian="LITTLE_ENDIAN";;
+  *) echo "Unknown $target" 1>&6; endian="0";;
+esac
 
-if test x"$enable_sim_switch" != x"" -a x"$enable_sim_switch" != x"no"; then
-  mv Makefile Makefile.tem
-  echo "Setting DGEN_FLAGS=-s" 1>&6
-  sed -e "s/^DGEN_FLAGS.*=.*\$/DGEN_FLAGS = -s/" < Makefile.tem > Makefile
-  rm -f Makefile.tem
-fi
+$srcdir/config.hdr config.h WITH_TARGET_BYTE_ORDER --enable-sim-endian "$enable_sim_endian" \
+  "" "0" "no" "0" "yes" "$endian" \
+  "b" "BIG_ENDIAN" "big" "BIG_ENDIAN" "big-endian" "BIG_ENDIAN" \
+  "B" "BIG_ENDIAN" "BIG" "BIG_ENDIAN" "BIG-ENDIAN" "BIG_ENDIAN" \
+  "l" "LITTLE_ENDIAN" "little" "LITTLE_ENDIAN" "little-endian" "LITTLE_ENDIAN" \
+  "L" "LITTLE_ENDIAN" "little" "LITTLE_ENDIAN" "little-endian" "LITTLE_ENDIAN" 1>&6
 
-if test x"$enable_sim_duplicate" != x"" -a x"$enable_sim_duplicate" != x"no"; then
-  mv Makefile Makefile.tem
-  echo "Setting IGEN_DUPLICATE=-e" 1>&6
-  sed -e "s/^IGEN_DUPLICATE.*=.*\$/IGEN_DUPLICATE = -e/" < Makefile.tem > Makefile
-  rm -f Makefile.tem
-fi
+$srcdir/config.hdr config.h WITH_HOST_BYTE_ORDER --enable-sim-hostendian "$enable_sim_hostendian" \
+  "b" "BIG_ENDIAN" "big" "BIG_ENDIAN" "big-endian" "BIG_ENDIAN" \
+  "B" "BIG_ENDIAN" "BIG" "BIG_ENDIAN" "BIG-ENDIAN" "BIG_ENDIAN" \
+  "l" "LITTLE_ENDIAN" "little" "LITTLE_ENDIAN" "little-endian" "LITTLE_ENDIAN" \
+  "L" "LITTLE_ENDIAN" "little" "LITTLE_ENDIAN" "little-endian" "LITTLE_ENDIAN" 1>&6
 
-if test x"$enable_sim_filter" = x"no"; then
-  mv Makefile Makefile.tem
-  echo "Setting IGEN_FILTER=" 1>&6
-  sed -e "s/^IGEN_FILTER.*=.*\$/IGEN_FILTER =/" < Makefile.tem > Makefile
-  rm -f Makefile.tem
+$srcdir/config.hdr config.h WITH_SMP --enable-sim-smp "$enable_sim_smp" \
+  "" "0" "no" "0" "yes" "2" "*" "$enable_sim_smp" 1>&6
 
-else
-  if test x"$enable_sim_filter" != x"yes" -a x"$enable_sim_filter" != x""; then
-    mv Makefile Makefile.tem
-    echo "Setting IGEN_FILTER= -f $enable_sim_filter" 1>&6
-    sed -e "s/^IGEN_FILTER.*=.*\$/IGEN_FILTER = -f $enable_sim_filter/" \
-      < Makefile.tem > Makefile
-    rm -f Makefile.tem
-  fi
-fi
+$srcdir/config.hdr config.h WITH_TARGET_WORD_BITSIZE --enable-sim-bitsize "$enable_sim_bitsize" \
+  "yes" "32" "32" "32" "32" "64" "64" 1>&6
 
-endian=""
-case x"$enable_sim_endian" in
-  xb* | xB*) endian="BIG_ENDIAN";;
-  xl* | xL*) endian="LITTLE_ENDIAN";;
-  xyes) case "$target" in
-         *powerpc-*) endian="BIG_ENDIAN";;
-         *powerpcle-*) endian="LITTLE_ENDIAN";;
-         *) echo "Unknown $target" 1>&6;;
-        esac;;
-esac
-if test x"$endian" != x""; then
-  mv Makefile Makefile.tem
-  echo "Setting SIM_ENDIAN=-DWITH_TARGET_BYTE_ORDER=$endian"
-  sed -e "s/^SIM_ENDIAN.*=.*\$/SIM_ENDIAN = -DWITH_TARGET_BYTE_ORDER=$endian/" \
-    < Makefile.tem > Makefile
-  rm -f Makefile.tem
-fi
+$srcdir/config.hdr config.h WITH_HOST_WORD_BITSIZE --enable-sim-hostbitsize "$enable_sim_hostbitsize" \
+  "yes" "32" "32" "32" "32" "64" "64" 1>&6
+
+$srcdir/config.hdr config.h WITH_ENVIRONMENT --enable-sim-env "$enable_sim_env" \
+  "yes" "0" \
+  "operating" "OPERATING_ENVIRONMENT" "os" "OPERATING_ENVIRONMENT" "oea" "OPERATING_ENVIRONMENT" \
+  "virtual" "VIRTUAL_ENVIRONMENT" "vea" "VIRTUAL_ENVIRONMENT" 1>&6
+
+$srcdir/config.hdr config.h WITH_TIME_BASE --enable-sim-timebase "$enable_sim_timebase" \
+  "no" "0" "yes" "1" 1>&6
+
+$srcdir/config.hdr config.h WITH_ALIGNMENT --enable-sim-alignment "$enable_sim_alignment" \
+  "no" "NONSTRICT_ALIGNMENT" "nonstrict" "NONSTRICT_ALIGNMENT" \
+  "yes" "STRICT_ALIGNMENT" "strict" "STRICT_ALIGNMENT" 1>&6
+
+$srcdir/config.hdr config.h WITH_FLOATING_POINT --enable-sim-float "$enable_sim_float" \
+  "no" "SOFT_FLOATING_POINT" "soft" "SOFT_FLOATING_POINT" \
+  "yes" "HARD_FLOATING_POINT" "hard" "HARD_FLOATING_POINT" 1>&6
+
+$srcdir/config.hdr config.h WITH_TRACE --enable-sim-trace "$enable_sim_trace" \
+  "no" "0" "yes" "1" 1>&6
+
+$srcdir/config.hdr config.h WITH_ASSERT --enable-sim-assert "$enable_sim_assert" \
+  "no" "0" "yes" "1" 1>&6
 
+$srcdir/config.hdr config.h WITH_MON --enable-sim-monitor "$enable_sim_monitor" \
+  "no" "0" "yes" "MONITOR_INSTRUCTION_ISSUE|MONITOR_LOAD_STORE_UNIT" \
+  "instruction" "MONITOR_INSTRUCTION_ISSUE" \
+  "memory" "MONITOR_LOAD_STORE_UNIT" 1>&6
index 59bc4b2..7b319f5 100644 (file)
@@ -31,13 +31,41 @@ AC_CHECK_HEADERS(string.h strings.h stdlib.h time.h sys/times.h)
 AC_OUTPUT(Makefile,
 [case x$CONFIG_HEADERS in xconfig.h:config.in) echo > stamp-h ;; esac])
 
+if test x"$enable_sim_cflags" != x"" -a x"$enable_sim_cflags" != x"no"; then
+  if test "$enable_sim_cflags" = "yes"; then
+    enable_sim_cflags="-fomit-frame-pointer,-O2"
+  fi
+  echo "Setting SIM_CFLAGS=$enable_sim_cflags" | sed -e "s/,/ /g" 1>&6
+  (echo; echo "# --enable-sim-cflags=$enable_sim_cflags";
+   echo "SIM_CFLAGS = $enable_sim_cflags" | sed -e "s/,/ /g") >> Makefile
+else
+  echo "Setting SIM_CFLAGS=" 1>&6
+  (echo; echo "# no --enable-sim-cflags"; echo "SIM_CFLAGS =") >> Makefile
+fi
+
+$srcdir/config.make Makefile CONFIG_FILE --enable-sim-config "$enable_sim_config" \
+  "" "std-config.h" "no" "std-config.h" "yes" "std-config.h" "*" "$enable_sim_config" 1>&6
+
+$srcdir/config.make Makefile IGEN_OPCODE_RULES --enable-sim-opcode "$enable_sim_opcode" \
+  "" "ppc-opcode-simple" "no" "ppc-opcode-simple" "yes" "ppc-opcode-simple" \
+  "complex" "ppc-opcode-complex" "simple" "ppc-opcode-simple" 1>&6
+
+$srcdir/config.make Makefile DGEN_FLAGS --enable-sim-switch "$enable_sim_switch" \
+  "" "" "no" "" "yes" "-s" 1>&6
+
+$srcdir/config.make Makefile IGEN_DUPLICATE --enable-sim-duplicate "$enable_sim_duplicate" \
+  "" "" "no" "" "yes" "-e" 1>&6
+
+$srcdir/config.make Makefile IGEN_FILTER --enable-sim-filter "$enable_sim_filter" \
+  "" "-f 64" "no" "" "yes" "-f 64" "*" "$enable_sim_filter" 1>&6
+
+flags=""
 if test x"$enable_sim_inline" != x""; then
-  flags=""
   case "$enable_sim_inline" in
     no)                flags="";;
-    0)         flags="-DDEFAULT_INLINE=0";;
-    yes | 2)   flags="-DDEFAULT_INLINE=2";;
-    1)         flags="-DDEFAULT_INLINE=1";;
+    0)         flags=" -DDEFAULT_INLINE=0";;
+    yes | 2)   flags=" -DDEFAULT_INLINE=2";;
+    1)         flags=" -DDEFAULT_INLINE=1";;
     *) for x in `echo "$enable_sim_inline" | sed -e "s/,/ /g"`; do
         case "$x" in
           *_INLINE=*)  flags="$flags -D$x";;
@@ -47,87 +75,68 @@ if test x"$enable_sim_inline" != x""; then
         esac
        done;;
   esac
-  if test x"$flags" != x""; then
-    mv Makefile Makefile.tem
-    echo "Setting INLINE_CFLAGS=$flags" 1>&6
-    sed -e "s/^INLINE_CFLAGS.*=.*\$/INLINE_CFLAGS =$flags/" \
-      < Makefile.tem > Makefile
-    rm -f Makefile.tem
-  fi
 fi
-
-if test x"$enable_sim_bswap" != x"" -a x"$enable_sim_bswap" != x"no"; then
-  mv Makefile Makefile.tem
-  echo "Setting BSWAP_CFLAGS=-DWITH_BSWAP=1" 1>&6
-  sed -e "s/^BSWAP_CFLAGS.*=.*\$/BSWAP_CFLAGS = -DWITH_BSWAP=1/" \
-    < Makefile.tem > Makefile
-  rm -f Makefile.tem
+if test x"$flags" != x""; then
+  echo "Setting INLINE_CFLAGS=$flags" 1>&6
+  (echo; echo "# --enable-sim-inline=$enable_sim_inline"; echo "INLINE_CFLAGS =$flags") >> Makefile
+else
+  echo "Setting INLINE_CFLAGS=" 1>&6
+  (echo; echo "# no --enable-sim-inline"; echo "INLINE_CFLAGS =") >> Makefile 
 fi
 
-if test x"$enable_sim_cflags" != x"" -a x"$enable_sim_cflags" != x"no"; then
-  if test "$enable_sim_cflags" = "yes"; then
-    enable_sim_cflags="-fomit-frame-pointer,-O2"
-  fi
-  mv Makefile Makefile.tem
-  echo "Setting SIM_CFLAGS=$enable_sim_cflags"
-  sed -e "s/^SIM_CFLAGS.*=.*\$/SIM_CFLAGS = $enable_sim_cflags/" -e "s/,/ /g"\
-    < Makefile.tem > Makefile
-  rm -f Makefile.tem
-fi
+$srcdir/config.hdr config.h WITH_BSWAP --enable-sim-bswap "$enable_sim_bswap" "yes" 1
 
-if test x"$enable_sim_complex" != x"" -a x"$enable_sim_complex" != x"no"; then
-  mv Makefile Makefile.tem
-  echo "Setting IGEN_OPCODE_RULES=ppc-opcode-complex" 1>&6
-  sed -e "s/^IGEN_OPCODE_RULES.*=.*\$/IGEN_OPCODE_RULES = ppc-opcode-complex/" \
-    < Makefile.tem > Makefile
-  rm -f Makefile.tem
-fi
+case "$target" in
+  *powerpc-*) endian="BIG_ENDIAN";;
+  *powerpcle-*) endian="LITTLE_ENDIAN";;
+  *) echo "Unknown $target" 1>&6; endian="0";;
+esac
 
-if test x"$enable_sim_switch" != x"" -a x"$enable_sim_switch" != x"no"; then
-  mv Makefile Makefile.tem
-  echo "Setting DGEN_FLAGS=-s" 1>&6
-  sed -e "s/^DGEN_FLAGS.*=.*\$/DGEN_FLAGS = -s/" < Makefile.tem > Makefile
-  rm -f Makefile.tem
-fi
+$srcdir/config.hdr config.h WITH_TARGET_BYTE_ORDER --enable-sim-endian "$enable_sim_endian" \
+  "" "0" "no" "0" "yes" "$endian" \
+  "b" "BIG_ENDIAN" "big" "BIG_ENDIAN" "big-endian" "BIG_ENDIAN" \
+  "B" "BIG_ENDIAN" "BIG" "BIG_ENDIAN" "BIG-ENDIAN" "BIG_ENDIAN" \
+  "l" "LITTLE_ENDIAN" "little" "LITTLE_ENDIAN" "little-endian" "LITTLE_ENDIAN" \
+  "L" "LITTLE_ENDIAN" "little" "LITTLE_ENDIAN" "little-endian" "LITTLE_ENDIAN" 1>&6
 
-if test x"$enable_sim_duplicate" != x"" -a x"$enable_sim_duplicate" != x"no"; then
-  mv Makefile Makefile.tem
-  echo "Setting IGEN_DUPLICATE=-e" 1>&6
-  sed -e "s/^IGEN_DUPLICATE.*=.*\$/IGEN_DUPLICATE = -e/" < Makefile.tem > Makefile
-  rm -f Makefile.tem
-fi
+$srcdir/config.hdr config.h WITH_HOST_BYTE_ORDER --enable-sim-hostendian "$enable_sim_hostendian" \
+  "b" "BIG_ENDIAN" "big" "BIG_ENDIAN" "big-endian" "BIG_ENDIAN" \
+  "B" "BIG_ENDIAN" "BIG" "BIG_ENDIAN" "BIG-ENDIAN" "BIG_ENDIAN" \
+  "l" "LITTLE_ENDIAN" "little" "LITTLE_ENDIAN" "little-endian" "LITTLE_ENDIAN" \
+  "L" "LITTLE_ENDIAN" "little" "LITTLE_ENDIAN" "little-endian" "LITTLE_ENDIAN" 1>&6
 
-if test x"$enable_sim_filter" = x"no"; then
-  mv Makefile Makefile.tem
-  echo "Setting IGEN_FILTER=" 1>&6
-  sed -e "s/^IGEN_FILTER.*=.*\$/IGEN_FILTER =/" < Makefile.tem > Makefile
-  rm -f Makefile.tem
+$srcdir/config.hdr config.h WITH_SMP --enable-sim-smp "$enable_sim_smp" \
+  "" "0" "no" "0" "yes" "2" "*" "$enable_sim_smp" 1>&6
 
-else
-  if test x"$enable_sim_filter" != x"yes" -a x"$enable_sim_filter" != x""; then
-    mv Makefile Makefile.tem
-    echo "Setting IGEN_FILTER= -f $enable_sim_filter" 1>&6
-    sed -e "s/^IGEN_FILTER.*=.*\$/IGEN_FILTER = -f $enable_sim_filter/" \
-      < Makefile.tem > Makefile
-    rm -f Makefile.tem
-  fi
-fi
+$srcdir/config.hdr config.h WITH_TARGET_WORD_BITSIZE --enable-sim-bitsize "$enable_sim_bitsize" \
+  "yes" "32" "32" "32" "32" "64" "64" 1>&6
 
-endian=""
-case x"$enable_sim_endian" in
-  xb* | xB*) endian="BIG_ENDIAN";;
-  xl* | xL*) endian="LITTLE_ENDIAN";;
-  xyes) case "$target" in
-         *powerpc-*) endian="BIG_ENDIAN";;
-         *powerpcle-*) endian="LITTLE_ENDIAN";;
-         *) echo "Unknown $target" 1>&6;;
-        esac;;
-esac
-if test x"$endian" != x""; then
-  mv Makefile Makefile.tem
-  echo "Setting SIM_ENDIAN=-DWITH_TARGET_BYTE_ORDER=$endian"
-  sed -e "s/^SIM_ENDIAN.*=.*\$/SIM_ENDIAN = -DWITH_TARGET_BYTE_ORDER=$endian/" \
-    < Makefile.tem > Makefile
-  rm -f Makefile.tem
-fi
+$srcdir/config.hdr config.h WITH_HOST_WORD_BITSIZE --enable-sim-hostbitsize "$enable_sim_hostbitsize" \
+  "yes" "32" "32" "32" "32" "64" "64" 1>&6
+
+$srcdir/config.hdr config.h WITH_ENVIRONMENT --enable-sim-env "$enable_sim_env" \
+  "yes" "0" \
+  "operating" "OPERATING_ENVIRONMENT" "os" "OPERATING_ENVIRONMENT" "oea" "OPERATING_ENVIRONMENT" \
+  "virtual" "VIRTUAL_ENVIRONMENT" "vea" "VIRTUAL_ENVIRONMENT" 1>&6
+
+$srcdir/config.hdr config.h WITH_TIME_BASE --enable-sim-timebase "$enable_sim_timebase" \
+  "no" "0" "yes" "1" 1>&6
+
+$srcdir/config.hdr config.h WITH_ALIGNMENT --enable-sim-alignment "$enable_sim_alignment" \
+  "no" "NONSTRICT_ALIGNMENT" "nonstrict" "NONSTRICT_ALIGNMENT" \
+  "yes" "STRICT_ALIGNMENT" "strict" "STRICT_ALIGNMENT" 1>&6
+
+$srcdir/config.hdr config.h WITH_FLOATING_POINT --enable-sim-float "$enable_sim_float" \
+  "no" "SOFT_FLOATING_POINT" "soft" "SOFT_FLOATING_POINT" \
+  "yes" "HARD_FLOATING_POINT" "hard" "HARD_FLOATING_POINT" 1>&6
+
+$srcdir/config.hdr config.h WITH_TRACE --enable-sim-trace "$enable_sim_trace" \
+  "no" "0" "yes" "1" 1>&6
+
+$srcdir/config.hdr config.h WITH_ASSERT --enable-sim-assert "$enable_sim_assert" \
+  "no" "0" "yes" "1" 1>&6
 
+$srcdir/config.hdr config.h WITH_MON --enable-sim-monitor "$enable_sim_monitor" \
+  "no" "0" "yes" "MONITOR_INSTRUCTION_ISSUE|MONITOR_LOAD_STORE_UNIT" \
+  "instruction" "MONITOR_INSTRUCTION_ISSUE" \
+  "memory" "MONITOR_LOAD_STORE_UNIT" 1>&6
diff --git a/sim/ppc/debug.h b/sim/ppc/debug.h
new file mode 100644 (file)
index 0000000..b300add
--- /dev/null
@@ -0,0 +1,118 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+    */
+
+
+#ifndef _DEBUG_H_
+#define _DEBUG_H_
+
+#include "filter_filename.h"
+
+typedef enum {
+  trace_invalid,
+  trace_tbd,
+  /**/
+  trace_gdb,
+  trace_os_emul,
+  /**/
+  trace_device_tree,
+  trace_devices,
+  trace_pass_device,
+  trace_console_device,
+  trace_icu_device,
+  trace_halt_device,
+  trace_register_device,
+  trace_vm_device,
+  trace_memory_device,
+  trace_htab_device,
+  trace_pte_device,
+  trace_binary_device,
+  trace_file_device,
+  trace_core_device,
+  trace_stack_device,
+  /**/
+  trace_semantics,
+  trace_idecode,
+  trace_alu,
+  /**/
+  trace_vm,
+  trace_core,
+  trace_psim,
+  trace_device_init,
+  trace_cpu,
+  trace_breakpoint,
+  nr_trace_options
+} trace_options;
+
+
+
+extern int ppc_trace[nr_trace_options];
+
+#if WITH_TRACE
+#define TRACE(OBJECT, ARGS) \
+do { \
+  if (ppc_trace[OBJECT]) { \
+    printf_filtered("%s:%d:%s: ", filter_filename(__FILE__), __LINE__, #OBJECT); \
+    printf_filtered ARGS; \
+  } \
+} while (0)
+/* issue */
+#define ITRACE(OBJECT, ARGS) \
+do { \
+  if (ppc_trace[OBJECT]) { \
+    printf_filtered("%s:%d:0x%x", my_prefix, cpu_nr(processor) + 1, cia); \
+    printf_filtered ARGS; \
+  } \
+} while (0)
+/* device */
+#define DTRACE(OBJECT, ARGS) \
+do { \
+  if (ppc_trace[trace_devices] || ppc_trace[trace_##OBJECT##_device]) { \
+    printf_filtered("%s:%d:%s: ", filter_filename(__FILE__), __LINE__, #OBJECT); \
+    printf_filtered ARGS; \
+  } \
+} while (0)
+#else
+#define TRACE(OBJECT, ARGS)
+#define ITRACE(OBJECT, ARGS)
+#define DTRACE(OBJECT, ARGS)
+#endif
+
+#if WITH_ASSERT
+#define ASSERT(EXPRESSION) \
+do { \
+  if (!(EXPRESSION)) { \
+    error("%s:%d: assertion failed - %s\n", \
+         filter_filename(__FILE__), __LINE__, #EXPRESSION); \
+  } \
+} while (0)
+#else
+#define ASSERT(EXPRESSION)
+#endif
+
+/* Parse OPTION updating the trace array */
+extern void
+trace_option(const char *option);
+
+/* Output the list of trace options */
+extern void
+trace_usage(void);
+
+
+#endif /* _DEBUG_H_ */
diff --git a/sim/ppc/emul_netbsd.c b/sim/ppc/emul_netbsd.c
new file mode 100644 (file)
index 0000000..e7d09c3
--- /dev/null
@@ -0,0 +1,1202 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+    */
+
+
+#ifndef _EMUL_NETBSD_C_
+#define _EMUL_NETBSD_C_
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/dirent.h>
+
+#define WITH_NetBSD_HOST (NetBSD >= 199306)
+#if WITH_NetBSD_HOST /* here NetBSD as that is what we're emulating */
+#include <sys/syscall.h> /* FIXME - should not be including this one */
+#include <sys/sysctl.h>
+extern int getdirentries(int fd, char *buf, int nbytes, long *basep);
+#endif
+
+#if (BSD < 199306) /* here BSD as just a bug */
+extern int errno;
+#endif
+
+#include "emul_generic.h"
+
+
+#ifndef STATIC_INLINE_EMUL_NETBSD
+#define STATIC_INLINE_EMUL_NETBSD STATIC_INLINE
+#endif
+
+
+#if WITH_NetBSD_HOST
+#define SYS(X) ASSERT(call == (SYS_##X))
+#else
+#define SYS(X)
+#endif
+
+#if WITH_NetBSD_HOST && (PATH_MAX != 1024)
+#error "PATH_MAX not 1024"
+#elif !defined(PATH_MAX)
+#define PATH_MAX 1024
+#endif
+
+
+STATIC_INLINE_EMUL_NETBSD void
+write_stat(unsigned_word addr,
+          struct stat buf,
+          cpu *processor,
+          unsigned_word cia)
+{
+  H2T(buf.st_dev);
+  H2T(buf.st_ino);
+  H2T(buf.st_mode);
+  H2T(buf.st_nlink);
+  H2T(buf.st_uid);
+  H2T(buf.st_gid);
+  H2T(buf.st_rdev);
+  H2T(buf.st_size);
+  H2T(buf.st_atime);
+  /* H2T(buf.st_spare1); */
+  H2T(buf.st_mtime);
+  /* H2T(buf.st_spare2); */
+  H2T(buf.st_ctime);
+  /* H2T(buf.st_spare3); */
+  H2T(buf.st_blksize);
+  H2T(buf.st_blocks);
+#if WITH_NetBSD_HOST
+  H2T(buf.st_flags);
+  H2T(buf.st_gen);
+#endif
+  emul_write_buffer(&buf, addr, sizeof(buf), processor, cia);
+}
+
+  
+#if NetBSD
+STATIC_INLINE_EMUL_NETBSD void
+write_statfs(unsigned_word addr,
+            struct statfs buf,
+            cpu *processor,
+            unsigned_word cia)
+{
+  H2T(buf.f_type);
+  H2T(buf.f_flags);
+  H2T(buf.f_bsize);
+  H2T(buf.f_iosize);
+  H2T(buf.f_blocks);
+  H2T(buf.f_bfree);
+  H2T(buf.f_bavail);
+  H2T(buf.f_files);
+  H2T(buf.f_ffree);
+  H2T(buf.f_fsid.val[0]);
+  H2T(buf.f_fsid.val[1]);
+  H2T(buf.f_owner);
+  /* f_spare[4]; */
+  /* f_fstypename[MFSNAMELEN]; */
+  /* f_mntonname[MNAMELEN]; */
+  /* f_mntfromname[MNAMELEN]; */
+  emul_write_buffer(&buf, addr, sizeof(buf), processor, cia);
+}
+#endif
+
+  
+STATIC_INLINE_EMUL_NETBSD void
+write_timeval(unsigned_word addr,
+             struct timeval t,
+             cpu *processor,
+             unsigned_word cia)
+{
+  H2T(t.tv_sec);
+  H2T(t.tv_usec);
+  emul_write_buffer(&t, addr, sizeof(t), processor, cia);
+}
+
+  
+STATIC_INLINE_EMUL_NETBSD void
+write_timezone(unsigned_word addr,
+              struct timezone tz,
+              cpu *processor,
+              unsigned_word cia)
+{
+  H2T(tz.tz_minuteswest);
+  H2T(tz.tz_dsttime);
+  emul_write_buffer(&tz, addr, sizeof(tz), processor, cia);
+}
+
+  
+#if WITH_NetBSD_HOST
+STATIC_INLINE_EMUL_NETBSD void
+write_direntries(unsigned_word addr,
+                char *buf,
+                int nbytes,
+                cpu *processor,
+                unsigned_word cia)
+{
+  while (nbytes > 0) {
+    struct dirent *out;
+    struct dirent *in = (struct dirent*)buf;
+    ASSERT(in->d_reclen <= nbytes);
+    out = (struct dirent*)zalloc(in->d_reclen);
+    bcopy(in, out, in->d_reclen);
+    H2T(out->d_fileno);
+    H2T(out->d_reclen);
+    H2T(out->d_type);
+    H2T(out->d_namlen);
+    emul_write_buffer(out, addr, in->d_reclen, processor, cia);
+    nbytes -= in->d_reclen;
+    addr += in->d_reclen;
+    buf += in->d_reclen;
+    zfree(out);
+  }
+}
+#endif
+
+
+STATIC_INLINE_EMUL_NETBSD void
+write_rusage(unsigned_word addr,
+            struct rusage rusage,
+            cpu *processor,
+            unsigned_word cia)
+{
+  H2T(rusage.ru_utime.tv_sec); /* user time used */
+  H2T(rusage.ru_utime.tv_usec);
+  H2T(rusage.ru_stime.tv_sec); /* system time used */
+  H2T(rusage.ru_stime.tv_usec);
+  H2T(rusage.ru_maxrss);          /* integral max resident set size */
+  H2T(rusage.ru_ixrss);           /* integral shared text memory size */
+  H2T(rusage.ru_idrss);           /* integral unshared data size */
+  H2T(rusage.ru_isrss);           /* integral unshared stack size */
+  H2T(rusage.ru_minflt);          /* page reclaims */
+  H2T(rusage.ru_majflt);          /* page faults */
+  H2T(rusage.ru_nswap);           /* swaps */
+  H2T(rusage.ru_inblock);         /* block input operations */
+  H2T(rusage.ru_oublock);         /* block output operations */
+  H2T(rusage.ru_msgsnd);          /* messages sent */
+  H2T(rusage.ru_msgrcv);          /* messages received */
+  H2T(rusage.ru_nsignals);        /* signals received */
+  H2T(rusage.ru_nvcsw);           /* voluntary context switches */
+  H2T(rusage.ru_nivcsw);          /* involuntary context switches */
+  emul_write_buffer(&rusage, addr, sizeof(rusage), processor, cia);
+}
+
+  
+STATIC_INLINE_EMUL_NETBSD void
+do_exit(emulation *emul,
+       unsigned call,
+       const int arg0,
+       cpu *processor,
+       unsigned_word cia)
+{
+  int status = (int)cpu_registers(processor)->gpr[arg0];
+  SYS(exit);
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("%d)\n", status);
+
+  cpu_halt(processor, cia, was_exited, status);
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_read(emulation *emul,
+       unsigned call,
+       const int arg0,
+       cpu *processor,
+       unsigned_word cia)
+{
+  void *scratch_buffer;
+  int d = (int)cpu_registers(processor)->gpr[arg0];
+  unsigned_word buf = cpu_registers(processor)->gpr[arg0+1];
+  int nbytes = cpu_registers(processor)->gpr[arg0+2];
+  int status;
+  int nr_moved;
+  SYS(read);
+  
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("%d, 0x%lx, %d", d, (long)buf, nbytes);
+
+  /* get a tempoary bufer */
+  scratch_buffer = zalloc(nbytes);
+  
+  /* check if buffer exists by reading it */
+  emul_read_buffer(scratch_buffer, buf, nbytes, processor, cia);
+  
+  /* read */
+#if 0
+  if (d == 0) {
+    status = fread (scratch_buffer, 1, nbytes, stdin);
+    if (status == 0 && ferror (stdin))
+      status = -1;
+  }
+#endif
+  status = read (d, scratch_buffer, nbytes);
+  
+  if (status == -1) {
+    cpu_registers(processor)->gpr[0] = errno;
+  } else {
+    cpu_registers(processor)->gpr[3] = status;
+    
+    if (status > 0)
+      emul_write_buffer(scratch_buffer, buf, status, processor, cia);
+  }
+  
+  zfree(scratch_buffer);
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_write(emulation *emul,
+        unsigned call,
+        const int arg0,
+        cpu *processor,
+        unsigned_word cia)
+{
+  void *scratch_buffer = NULL;
+  int nr_moved;
+  int d = (int)cpu_registers(processor)->gpr[arg0];
+  unsigned_word buf = cpu_registers(processor)->gpr[arg0+1];
+  int nbytes = cpu_registers(processor)->gpr[arg0+2];
+  int status;
+  SYS(write);
+  
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("%d, 0x%lx, %d", d, (long)buf, nbytes);
+
+  /* get a tempoary bufer */
+  scratch_buffer = zalloc(nbytes); /* FIXME - nbytes == 0 */
+  
+  /* copy in */
+  nr_moved = vm_data_map_read_buffer(cpu_data_map(processor),
+                                    scratch_buffer,
+                                    buf,
+                                    nbytes);
+  if (nr_moved != nbytes) {
+    /* FIXME - should handle better */
+    error("system_call()write copy failed (nr_moved=%d != nbytes=%d)\n",
+         nr_moved, nbytes);
+  }
+  
+  /* write */
+  status = write(d, scratch_buffer, nbytes);
+  emul_write_status(processor, status, errno);
+  zfree(scratch_buffer);
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_open(emulation *emul,
+       unsigned call,
+       const int arg0,
+       cpu *processor,
+       unsigned_word cia)
+{
+  unsigned_word path_addr = cpu_registers(processor)->gpr[arg0];
+  char path_buf[PATH_MAX];
+  char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia);
+  int flags = (int)cpu_registers(processor)->gpr[arg0+1];
+  int mode = (int)cpu_registers(processor)->gpr[arg0+2];
+
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("0x%lx [%s], 0x%x, 0x%x", (long)path_addr, path, flags, mode);
+
+  SYS(open);
+  emul_write_status(processor, open(path, flags, mode), errno);
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_close(emulation *emul,
+        unsigned call,
+        const int arg0,
+        cpu *processor,
+        unsigned_word cia)
+{
+  int d = (int)cpu_registers(processor)->gpr[arg0];
+
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("%d", d);
+
+  SYS(close);
+  emul_write_status(processor, close(d), errno);
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_break(emulation *emul,
+        unsigned call,
+        const int arg0,
+        cpu *processor,
+        unsigned_word cia)
+     /* just pass this onto the `vm' device */
+{
+  psim *system = cpu_system(processor);
+  const device *vm = psim_device(system, "/vm");
+
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("0x%lx", (long)cpu_registers(processor)->gpr[arg0]);
+
+  SYS(break);
+  vm->callback->ioctl(vm,
+                     system,
+                     processor,
+                     cia,
+                     0, /*ioctl*/
+                     NULL); /*ioctl-data*/
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_getpid(emulation *emul,
+         unsigned call,
+         const int arg0,
+         cpu *processor,
+         unsigned_word cia)
+{
+  SYS(getpid);
+  cpu_registers(processor)->gpr[3] = (int)getpid();
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_getuid(emulation *emul,
+         unsigned call,
+         const int arg0,
+         cpu *processor,
+         unsigned_word cia)
+{
+  SYS(getuid);
+  cpu_registers(processor)->gpr[3] = (int)getuid();
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_geteuid(emulation *emul,
+          unsigned call,
+          const int arg0,
+          cpu *processor,
+          unsigned_word cia)
+{
+  SYS(geteuid);
+  cpu_registers(processor)->gpr[3] = (int)geteuid();
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_kill(emulation *emul,
+       unsigned call,
+       const int arg0,
+       cpu *processor,
+       unsigned_word cia)
+{
+  pid_t pid = cpu_registers(processor)->gpr[arg0];
+  int sig = cpu_registers(processor)->gpr[arg0+1];
+
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("%d, %d", (int)pid, sig);
+
+  SYS(kill);
+  printf_filtered("SYS_kill at 0x%x - more to this than just being killed\n",
+                 cia);
+  cpu_halt(processor, cia, was_signalled, sig);
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_dup(emulation *emul,
+       unsigned call,
+       const int arg0,
+       cpu *processor,
+       unsigned_word cia)
+{
+  int oldd = cpu_registers(processor)->gpr[arg0];
+  int status = dup(oldd);
+
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("%d", oldd);
+
+  SYS(dup);
+  emul_write_status(processor, status, errno);
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_getegid(emulation *emul,
+          unsigned call,
+          const int arg0,
+          cpu *processor,
+          unsigned_word cia)
+{
+  SYS(getegid);
+  cpu_registers(processor)->gpr[3] = (int)getegid();
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_getgid(emulation *emul,
+         unsigned call,
+         const int arg0,
+         cpu *processor,
+         unsigned_word cia)
+{
+  SYS(getgid);
+  cpu_registers(processor)->gpr[3] = (int)getgid();
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_sigprocmask(emulation *emul,
+              unsigned call,
+              const int arg0,
+              cpu *processor,
+              unsigned_word cia)
+{
+  natural_word how = cpu_registers(processor)->gpr[arg0];
+  unsigned_word set = cpu_registers(processor)->gpr[arg0+1];
+  unsigned_word oset = cpu_registers(processor)->gpr[arg0+2];
+  SYS(sigprocmask);
+
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("%ld, 0x%ld, 0x%ld", (long)how, (long)set, (long)oset);
+
+  cpu_registers(processor)->gpr[3] = 0;
+  cpu_registers(processor)->gpr[4] = set;
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_ioctl(emulation *emul,
+        unsigned call,
+        const int arg0,
+        cpu *processor,
+        unsigned_word cia)
+{
+  int d = cpu_registers(processor)->gpr[arg0];
+  unsigned request = cpu_registers(processor)->gpr[arg0+1];
+  unsigned_word argp_addr = cpu_registers(processor)->gpr[arg0+2];
+
+#if !WITH_NetBSD_HOST
+  cpu_registers(processor)->gpr[arg0] = 0; /* just succeed */
+#else
+  unsigned param_len = IOCPARM_LEN(request);
+  unsigned basecmd = IOCBASECMD(request);
+  unsigned group = IOCGROUP(request);
+  unsigned dir = request & IOC_DIRMASK;
+  char *argp = NULL;
+  int status;
+  SYS(ioctl);
+  /* what we haven't done */
+  if (dir & IOC_IN /* write into the io device */
+      || dir & IOC_OUT
+      || !(dir & IOC_VOID))
+    error("do_ioctl() read or write of parameter not implemented\n");
+  status = ioctl(d, request, NULL);
+  emul_write_status(processor, status, errno);
+#endif
+
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("%d, 0x%x, 0x%lx", d, request, (long)argp_addr);
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_umask(emulation *emul,
+        unsigned call,
+        const int arg0,
+        cpu *processor,
+        unsigned_word cia)
+{
+  int mask = cpu_registers(processor)->gpr[arg0];
+
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("0%o", mask);
+
+  SYS(umask);
+  cpu_registers(processor)->gpr[3] = umask(mask);
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_dup2(emulation *emul,
+       unsigned call,
+       const int arg0,
+       cpu *processor,
+       unsigned_word cia)
+{
+  int oldd = cpu_registers(processor)->gpr[arg0];
+  int newd = cpu_registers(processor)->gpr[arg0+1];
+  int status = dup2(oldd, newd);
+
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("%d, %d", oldd, newd);
+
+  SYS(dup2);
+  emul_write_status(processor, status, errno);
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_fcntl(emulation *emul,
+        unsigned call,
+        const int arg0,
+        cpu *processor,
+        unsigned_word cia)
+{
+  int fd = cpu_registers(processor)->gpr[arg0];
+  int cmd = cpu_registers(processor)->gpr[arg0+1];
+  int arg = cpu_registers(processor)->gpr[arg0+2];
+  int status;
+
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("%d, %d, %d", fd, cmd, arg);
+
+  SYS(fcntl);
+  status = fcntl(fd, cmd, arg);
+  emul_write_status(processor, status, errno);
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_gettimeofday(emulation *emul,
+               unsigned call,
+               const int arg0,
+               cpu *processor,
+               unsigned_word cia)
+{
+  unsigned_word t_addr = cpu_registers(processor)->gpr[arg0];
+  unsigned_word tz_addr = cpu_registers(processor)->gpr[arg0+1];
+  struct timeval t;
+  struct timezone tz;
+  int status = gettimeofday((t_addr != 0 ? &t : NULL),
+                           (tz_addr != 0 ? &tz : NULL));
+
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("0x%lx, 0x%lx", (long)t_addr, (long)tz_addr);
+
+  SYS(gettimeofday);
+  emul_write_status(processor, status, errno);
+  if (status == 0) {
+    if (t_addr != 0)
+      write_timeval(t_addr, t, processor, cia);
+    if (tz_addr != 0)
+      write_timezone(tz_addr, tz, processor, cia);
+  }
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_getrusage(emulation *emul,
+            unsigned call,
+            const int arg0,
+            cpu *processor,
+            unsigned_word cia)
+{
+  int who = cpu_registers(processor)->gpr[arg0];
+  unsigned_word rusage_addr = cpu_registers(processor)->gpr[arg0+1];
+  struct rusage rusage;
+  int status = getrusage(who, (rusage_addr != 0 ? &rusage : NULL));
+
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("%d, 0x%lx", who, (long)rusage_addr);
+
+  SYS(getrusage);
+  emul_write_status(processor, status, errno);
+  if (status == 0) {
+    if (rusage_addr != 0)
+      write_rusage(rusage_addr, rusage, processor, cia);
+  }
+}
+
+
+#if !WITH_NetBSD_HOST
+#define do_fstatfs 0
+#else
+STATIC_INLINE_EMUL_NETBSD void
+do_fstatfs(emulation *emul,
+          unsigned call,
+          const int arg0,
+          cpu *processor,
+          unsigned_word cia)
+{
+  int fd = cpu_registers(processor)->gpr[arg0];
+  unsigned_word buf_addr = cpu_registers(processor)->gpr[arg0+1];
+  struct statfs buf;
+  int status;
+
+  if (WITH_TRACE && ppc_trace[trace_os_emul])
+    printf_filtered ("%d, 0x%lx", fd, (long)buf_addr);
+
+  SYS(fstatfs);
+  status = fstatfs(fd, (buf_addr == 0 ? NULL : &buf));
+  emul_write_status(processor, status, errno);
+  if (status == 0) {
+    if (buf_addr != 0)
+      write_statfs(buf_addr, buf, processor, cia);
+  }
+}
+#endif
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_stat(emulation *emul,
+       unsigned call,
+       const int arg0,
+       cpu *processor,
+       unsigned_word cia)
+{
+  char path_buf[PATH_MAX];
+  unsigned_word path_addr = cpu_registers(processor)->gpr[arg0];
+  unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[arg0+1];
+  char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia);
+  struct stat buf;
+  int status;
+  SYS(stat);
+  status = stat(path, &buf);
+  emul_write_status(processor, status, errno);
+  if (status == 0)
+    write_stat(stat_buf_addr, buf, processor, cia);
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_fstat(emulation *emul,
+        unsigned call,
+        const int arg0,
+        cpu *processor,
+        unsigned_word cia)
+{
+  int fd = cpu_registers(processor)->gpr[arg0];
+  unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[arg0+1];
+  struct stat buf;
+  SYS(fstat);
+  emul_write_status(processor, fstat(fd, &buf), errno);
+  write_stat(stat_buf_addr, buf, processor, cia);
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_lstat(emulation *emul,
+        unsigned call,
+        const int arg0,
+        cpu *processor,
+        unsigned_word cia)
+{
+  char path_buf[PATH_MAX];
+  unsigned_word path_addr = cpu_registers(processor)->gpr[arg0];
+  char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia);
+  unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[arg0+1];
+  struct stat buf;
+  SYS(lstat);
+  emul_write_status(processor, stat(path, &buf), errno);
+  write_stat(stat_buf_addr, buf, processor, cia);
+}
+
+
+#if !WITH_NetBSD_HOST
+#define do_getdirentries 0
+#else
+STATIC_INLINE_EMUL_NETBSD void
+do_getdirentries(emulation *emul,
+                unsigned call,
+                const int arg0,
+                cpu *processor,
+                unsigned_word cia)
+{
+  int fd = cpu_registers(processor)->gpr[arg0];
+  unsigned_word buf_addr = cpu_registers(processor)->gpr[arg0+1];
+  char *buf;
+  int nbytes = cpu_registers(processor)->gpr[arg0+2];
+  unsigned_word basep_addr = cpu_registers(processor)->gpr[arg0+3];
+  long basep;
+  int status;
+  SYS(getdirentries);
+  if (buf_addr != 0 && nbytes >= 0)
+    buf = zalloc(nbytes);
+  else
+    buf = NULL;
+  status = getdirentries(fd,
+                        (buf_addr == 0 ? NULL : buf),
+                        nbytes,
+                        (basep_addr == 0 ? NULL : &basep));
+  emul_write_status(processor, status, errno);
+  if (basep_addr != 0)
+    emul_write_word(basep_addr, basep, processor, cia);
+  if (status > 0)
+    write_direntries(buf_addr, buf, status, processor, cia);
+  if (buf != NULL)
+    zfree(buf);
+}
+#endif
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do___syscall(emulation *emul,
+            unsigned call,
+            const int arg0,
+            cpu *processor,
+            unsigned_word cia)
+{
+  SYS(__syscall);
+  emul_do_call(emul,
+              cpu_registers(processor)->gpr[arg0],
+              arg0 + 1,
+              processor,
+              cia);
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do_lseek(emulation *emul,
+        unsigned call,
+        const int arg0,
+        cpu *processor,
+        unsigned_word cia)
+{
+  int fildes = cpu_registers(processor)->gpr[arg0];
+  off_t offset = emul_read_gpr64(processor, arg0+2);
+  int whence = cpu_registers(processor)->gpr[arg0+4];
+  off_t status;
+  SYS(lseek);
+  status = lseek(fildes, offset, whence);
+  if (status == -1)
+    emul_write_status(processor, -1, errno);
+  else {
+    emul_write_gpr64(processor, 3, status);
+  }
+}
+
+
+STATIC_INLINE_EMUL_NETBSD void
+do___sysctl(emulation *emul,
+           unsigned call,
+           const int arg0,
+           cpu *processor,
+           unsigned_word cia)
+{
+  /* call the arguments by their real name */
+  unsigned_word name = cpu_registers(processor)->gpr[arg0];
+  natural_word namelen = cpu_registers(processor)->gpr[arg0+1];
+  unsigned_word oldp = cpu_registers(processor)->gpr[arg0+2];
+  unsigned_word oldlenp = cpu_registers(processor)->gpr[arg0+3];
+  natural_word oldlen;
+  natural_word mib;
+  natural_word int_val;
+  SYS(__sysctl);
+
+  /* pluck out the management information base id */
+  if (namelen < 1)
+    error("system_call()SYS___sysctl bad name[0]\n");
+  mib = vm_data_map_read_word(cpu_data_map(processor),
+                             name,
+                             processor,
+                             cia);
+  name += sizeof(mib);
+  
+  /* see what to do with it ... */
+  switch (mib) {
+  case 6/*CTL_HW*/:
+#if WITH_NetBSD_HOST && (CTL_HW != 6)
+#  error "CTL_HW"
+#endif
+    if (namelen < 2)
+      error("system_call()SYS___sysctl - CTL_HW - bad name[1]\n");
+    mib = vm_data_map_read_word(cpu_data_map(processor),
+                               name,
+                               processor,
+                               cia);
+    name += sizeof(mib);
+    switch (mib) {
+    case 7/*HW_PAGESIZE*/:
+#if WITH_NetBSD_HOST && (HW_PAGESIZE != 7)
+#  error "HW_PAGESIZE"
+#endif
+      oldlen = vm_data_map_read_word(cpu_data_map(processor),
+                                    oldlenp,
+                                    processor,
+                                    cia);
+      if (sizeof(natural_word) > oldlen)
+       error("system_call()sysctl - CTL_HW.HW_PAGESIZE - to small\n");
+      int_val = 8192;
+      oldlen = sizeof(int_val);
+      emul_write_word(oldp, int_val, processor, cia);
+      emul_write_word(oldlenp, oldlen, processor, cia);
+      break;
+    default:
+      error("sysctl() CTL_HW.%d unknown\n", mib);
+      break;
+    }
+    break;
+  default:
+    error("sysctl() name[0]=%s unknown\n", (int)mib);
+    break;
+  }
+  cpu_registers(processor)->gpr[3] = 0;
+}
+
+
+
+static emul_call_descriptor netbsd_descriptors[] = {
+  /* 0 */ { 0, "syscall", { 0, }, 0 },
+  /* 1 */ { do_exit, "exit", { 0, }, 0 },
+  /* 2 */ { 0, "fork", { 0, }, 0 },      
+  /* 3 */ { do_read, "read", { 0, }, 0 },
+  /* 4 */ { do_write, "write", { 0, }, 0 },
+  /* 5 */ { do_open, "open", { 0, }, 0 },
+  /* 6 */ { do_close, "close", { 0, }, 0 },
+  /* 7 */ { 0, "wait4", { 0, }, 0 },
+  { 0, }, /* 8 is old creat */
+  /* 9 */ { 0, "link", { 0, }, 0 },
+  /* 10 */ { 0, "unlink", { 0, }, 0 },
+  { 0, }, /* 11 is obsolete execv */
+  /* 12 */ { 0, "chdir", { 0, }, 0 },
+  /* 13 */ { 0, "fchdir", { 0, }, 0 },
+  /* 14 */ { 0, "mknod", { 0, }, 0 },
+  /* 15 */ { 0, "chmod", { 0, }, 0 },
+  /* 16 */ { 0, "chown", { 0, }, 0 },
+  /* 17 */ { do_break, "break", { 0, }, 0 },
+  /* 18 */ { 0, "getfsstat", { 0, }, 0 },
+  { 0, }, /* 19 is old lseek */
+  /* 20 */ { do_getpid, "getpid", { 0, }, 0 },
+  /* 21 */ { 0, "mount", { 0, }, 0 },
+  /* 22 */ { 0, "unmount", { 0, }, 0 },
+  /* 23 */ { 0, "setuid", { 0, }, 0 },
+  /* 24 */ { do_getuid, "getuid", { 0, }, 0 },
+  /* 25 */ { do_geteuid, "geteuid", { 0, }, 0 },
+  /* 26 */ { 0, "ptrace", { 0, }, 0 },
+  /* 27 */ { 0, "recvmsg", { 0, }, 0 },
+  /* 28 */ { 0, "sendmsg", { 0, }, 0 },
+  /* 29 */ { 0, "recvfrom", { 0, }, 0 },
+  /* 30 */ { 0, "accept", { 0, }, 0 },
+  /* 31 */ { 0, "getpeername", { 0, }, 0 },
+  /* 32 */ { 0, "getsockname", { 0, }, 0 },
+  /* 33 */ { 0, "access", { 0, }, 0 },
+  /* 34 */ { 0, "chflags", { 0, }, 0 },
+  /* 35 */ { 0, "fchflags", { 0, }, 0 },
+  /* 36 */ { 0, "sync", { 0, }, 0 },
+  /* 37 */ { do_kill, "kill", { 0, }, 0 },
+  { 0, }, /* 38 is old stat */
+  /* 39 */ { 0, "getppid", { 0, }, 0 },
+  { 0, }, /* 40 is old lstat */
+  /* 41 */ { do_dup, "dup", { 0, }, 0 },
+  /* 42 */ { 0, "pipe", { 0, }, 0 },
+  /* 43 */ { do_getegid, "getegid", { 0, }, 0 },
+  /* 44 */ { 0, "profil", { 0, }, 0 },
+  /* 45 */ { 0, "ktrace", { 0, }, 0 },
+  /* 46 */ { 0, "sigaction", { 0, }, 0 },
+  /* 47 */ { do_getgid, "getgid", { 0, }, 0 },
+  /* 48 */ { do_sigprocmask, "sigprocmask", { 0, }, 0 },
+  /* 49 */ { 0, "getlogin", { 0, }, 0 },
+  /* 50 */ { 0, "setlogin", { 0, }, 0 },
+  /* 51 */ { 0, "acct", { 0, }, 0 },
+  /* 52 */ { 0, "sigpending", { 0, }, 0 },
+  /* 53 */ { 0, "sigaltstack", { 0, }, 0 },
+  /* 54 */ { do_ioctl, "ioctl", { 0, }, 0 },
+  /* 55 */ { 0, "reboot", { 0, }, 0 },
+  /* 56 */ { 0, "revoke", { 0, }, 0 },
+  /* 57 */ { 0, "symlink", { 0, }, 0 },
+  /* 58 */ { 0, "readlink", { 0, }, 0 },
+  /* 59 */ { 0, "execve", { 0, }, 0 },
+  /* 60 */ { do_umask, "umask", { 0, }, 0 },
+  /* 61 */ { 0, "chroot", { 0, }, 0 },
+  { 0, }, /* 62 is old fstat */
+  { 0, }, /* 63 is old getkerninfo */
+  { 0, }, /* 64 is old getpagesize */
+  /* 65 */ { 0, "msync", { 0, }, 0 },
+  /* 66 */ { 0, "vfork", { 0, }, 0 },
+  { 0, }, /* 67 is obsolete vread */
+  { 0, }, /* 68 is obsolete vwrite */
+  /* 69 */ { 0, "sbrk", { 0, }, 0 },
+  /* 70 */ { 0, "sstk", { 0, }, 0 },
+  { 0, }, /* 71 is old mmap */
+  /* 72 */ { 0, "vadvise", { 0, }, 0 },
+  /* 73 */ { 0, "munmap", { 0, }, 0 },
+  /* 74 */ { 0, "mprotect", { 0, }, 0 },
+  /* 75 */ { 0, "madvise", { 0, }, 0 },
+  { 0, }, /* 76 is obsolete vhangup */
+  { 0, }, /* 77 is obsolete vlimit */
+  /* 78 */ { 0, "mincore", { 0, }, 0 },
+  /* 79 */ { 0, "getgroups", { 0, }, 0 },
+  /* 80 */ { 0, "setgroups", { 0, }, 0 },
+  /* 81 */ { 0, "getpgrp", { 0, }, 0 },
+  /* 82 */ { 0, "setpgid", { 0, }, 0 },
+  /* 83 */ { 0, "setitimer", { 0, }, 0 },
+  { 0, }, /* 84 is old wait */
+  /* 85 */ { 0, "swapon", { 0, }, 0 },
+  /* 86 */ { 0, "getitimer", { 0, }, 0 },
+  { 0, }, /* 87 is old gethostname */
+  { 0, }, /* 88 is old sethostname */
+  { 0, }, /* 89 is old getdtablesize */
+  { do_dup2, "dup2", { 0, }, 0 },
+  { 0, }, /* 91 */
+  /* 92 */ { do_fcntl, "fcntl", { 0, }, 0 },
+  /* 93 */ { 0, "select", { 0, }, 0 },
+  { 0, }, /* 94 */
+  /* 95 */ { 0, "fsync", { 0, }, 0 },
+  /* 96 */ { 0, "setpriority", { 0, }, 0 },
+  /* 97 */ { 0, "socket", { 0, }, 0 },
+  /* 98 */ { 0, "connect", { 0, }, 0 },
+  { 0, }, /* 99 is old accept */
+  /* 100 */ { 0, "getpriority", { 0, }, 0 },
+  { 0, }, /* 101 is old send */
+  { 0, }, /* 102 is old recv */
+  /* 103 */ { 0, "sigreturn", { 0, }, 0 },
+  /* 104 */ { 0, "bind", { 0, }, 0 },
+  /* 105 */ { 0, "setsockopt", { 0, }, 0 },
+  /* 106 */ { 0, "listen", { 0, }, 0 },
+  { 0, }, /* 107 is obsolete vtimes */
+  { 0, }, /* 108 is old sigvec */
+  { 0, }, /* 109 is old sigblock */
+  { 0, }, /* 110 is old sigsetmask */
+  /* 111 */ { 0, "sigsuspend", { 0, }, 0 },
+  { 0, }, /* 112 is old sigstack */
+  { 0, }, /* 113 is old recvmsg */
+  { 0, }, /* 114 is old sendmsg */
+  /* - is obsolete vtrace */ { 0, "vtrace      115", { 0, }, 0 },
+  /* 116 */ { do_gettimeofday, "gettimeofday", { 0, }, 0 },
+  /* 117 */ { do_getrusage, "getrusage", { 0, }, 0 },
+  /* 118 */ { 0, "getsockopt", { 0, }, 0 },
+  /* 119 */ { 0, "resuba", { 0, }, 0 },
+  /* 120 */ { 0, "readv", { 0, }, 0 },
+  /* 121 */ { 0, "writev", { 0, }, 0 },
+  /* 122 */ { 0, "settimeofday", { 0, }, 0 },
+  /* 123 */ { 0, "fchown", { 0, }, 0 },
+  /* 124 */ { 0, "fchmod", { 0, }, 0 },
+  { 0, }, /* 125 is old recvfrom */
+  { 0, }, /* 126 is old setreuid */
+  { 0, }, /* 127 is old setregid */
+  /* 128 */ { 0, "rename", { 0, }, 0 },
+  { 0, }, /* 129 is old truncate */
+  { 0, }, /* 130 is old ftruncate */
+  /* 131 */ { 0, "flock", { 0, }, 0 },
+  /* 132 */ { 0, "mkfifo", { 0, }, 0 },
+  /* 133 */ { 0, "sendto", { 0, }, 0 },
+  /* 134 */ { 0, "shutdown", { 0, }, 0 },
+  /* 135 */ { 0, "socketpair", { 0, }, 0 },
+  /* 136 */ { 0, "mkdir", { 0, }, 0 },
+  /* 137 */ { 0, "rmdir", { 0, }, 0 },
+  /* 138 */ { 0, "utimes", { 0, }, 0 },
+  { 0, }, /* 139 is obsolete 4.2 sigreturn */
+  /* 140 */ { 0, "adjtime", { 0, }, 0 },
+  { 0, }, /* 141 is old getpeername */
+  { 0, }, /* 142 is old gethostid */
+  { 0, }, /* 143 is old sethostid */
+  { 0, }, /* 144 is old getrlimit */
+  { 0, }, /* 145 is old setrlimit */
+  { 0, }, /* 146 is old killpg */
+  /* 147 */ { 0, "setsid", { 0, }, 0 },
+  /* 148 */ { 0, "quotactl", { 0, }, 0 },
+  { 0, }, /* 149 is old quota */
+  { 0, }, /* 150 is old getsockname */
+  { 0, }, /* 151 */
+  { 0, }, /* 152 */
+  { 0, }, /* 153 */
+  { 0, }, /* 154 */
+  /* 155 */ { 0, "nfssvc", { 0, }, 0 },
+  { 0, }, /* 156 is old getdirentries */
+  /* 157 */ { 0, "statfs", { 0, }, 0 },
+  /* 158 */ { do_fstatfs, "fstatfs", { 0, }, 0 },
+  { 0, }, /* 159 */
+  { 0, }, /* 160 */
+  /* 161 */ { 0, "getfh", { 0, }, 0 },
+  { 0, }, /* 162 is old getdomainname */
+  { 0, }, /* 163 is old setdomainname */
+  { 0, }, /* 164 is old uname */
+  /* 165 */ { 0, "sysarch", { 0, }, 0 },
+  { 0, }, /* 166 */
+  { 0, }, /* 167 */
+  { 0, }, /* 168 */
+  /* 169 */ { 0, "semsys", { 0, }, 0 },
+  /* 170 */ { 0, "msgsys", { 0, }, 0 },
+  /* 171 */ { 0, "shmsys", { 0, }, 0 },
+  { 0, }, /* 172 */
+  { 0, }, /* 173 */
+  { 0, }, /* 174 */
+  { 0, }, /* 175 */
+  { 0, }, /* 176 */
+  { 0, }, /* 177 */
+  { 0, }, /* 178 */
+  { 0, }, /* 179 */
+  { 0, }, /* 180 */
+  /* 181 */ { 0, "setgid", { 0, }, 0 },
+  /* 182 */ { 0, "setegid", { 0, }, 0 },
+  /* 183 */ { 0, "seteuid", { 0, }, 0 },
+  /* 184 */ { 0, "lfs_bmapv", { 0, }, 0 },
+  /* 185 */ { 0, "lfs_markv", { 0, }, 0 },
+  /* 186 */ { 0, "lfs_segclean", { 0, }, 0 },
+  /* 187 */ { 0, "lfs_segwait", { 0, }, 0 },
+  /* 188 */ { do_stat, "stat", { 0, }, 0 },
+  /* 189 */ { do_fstat, "fstat", { 0, }, 0 },
+  /* 190 */ { do_lstat, "lstat", { 0, }, 0 },
+  /* 191 */ { 0, "pathconf", { 0, }, 0 },
+  /* 192 */ { 0, "fpathconf", { 0, }, 0 },
+  { 0, }, /* 193 */
+  /* 194 */ { 0, "getrlimit", { 0, }, 0 },
+  /* 195 */ { 0, "setrlimit", { 0, }, 0 },
+  /* 196 */ { do_getdirentries, "getdirentries", { 0, }, 0 },
+  /* 197 */ { 0, "mmap", { 0, }, 0 },
+  /* 198 */ { do___syscall, "__syscall", { 0, }, 0 },
+  /* 199 */ { do_lseek, "lseek", { 0, }, 0 },
+  /* 200 */ { 0, "truncate", { 0, }, 0 },
+  /* 201 */ { 0, "ftruncate", { 0, }, 0 },
+  /* 202 */ { do___sysctl, "__sysctl", { 0, }, 0 },
+  /* 203 */ { 0, "mlock", { 0, }, 0 },
+  /* 204 */ { 0, "munlock", { 0, }, 0 },
+};
+    
+static char *(netbsd_error_names[]) = {
+  /* 0 */ "ESUCCESS",
+  /* 1 */ "EPERM",
+  /* 2 */ "ENOENT",
+  /* 3 */ "ESRCH",
+  /* 4 */ "EINTR",
+  /* 5 */ "EIO",
+  /* 6 */ "ENXIO",
+  /* 7 */ "E2BIG",
+  /* 8 */ "ENOEXEC",
+  /* 9 */ "EBADF",
+  /* 10 */ "ECHILD",
+  /* 11 */ "EDEADLK",
+  /* 12 */ "ENOMEM",
+  /* 13 */ "EACCES",
+  /* 14 */ "EFAULT",
+  /* 15 */ "ENOTBLK",
+  /* 16 */ "EBUSY",
+  /* 17 */ "EEXIST",
+  /* 18 */ "EXDEV",
+  /* 19 */ "ENODEV",
+  /* 20 */ "ENOTDIR",
+  /* 21 */ "EISDIR",
+  /* 22 */ "EINVAL",
+  /* 23 */ "ENFILE",
+  /* 24 */ "EMFILE",
+  /* 25 */ "ENOTTY",
+  /* 26 */ "ETXTBSY",
+  /* 27 */ "EFBIG",
+  /* 28 */ "ENOSPC",
+  /* 29 */ "ESPIPE",
+  /* 30 */ "EROFS",
+  /* 31 */ "EMLINK",
+  /* 32 */ "EPIPE",
+  /* 33 */ "EDOM",
+  /* 34 */ "ERANGE",
+  /* 35 */ "EAGAIN",
+  /* 36 */ "EINPROGRESS",
+  /* 37 */ "EALREADY",
+  /* 38 */ "ENOTSOCK",
+  /* 39 */ "EDESTADDRREQ",
+  /* 40 */ "EMSGSIZE",
+  /* 41 */ "EPROTOTYPE",
+  /* 42 */ "ENOPROTOOPT",
+  /* 43 */ "EPROTONOSUPPORT",
+  /* 44 */ "ESOCKTNOSUPPORT",
+  /* 45 */ "EOPNOTSUPP",
+  /* 46 */ "EPFNOSUPPORT",
+  /* 47 */ "EAFNOSUPPORT",
+  /* 48 */ "EADDRINUSE",
+  /* 49 */ "EADDRNOTAVAIL",
+  /* 50 */ "ENETDOWN",
+  /* 51 */ "ENETUNREACH",
+  /* 52 */ "ENETRESET",
+  /* 53 */ "ECONNABORTED",
+  /* 54 */ "ECONNRESET",
+  /* 55 */ "ENOBUFS",
+  /* 56 */ "EISCONN",
+  /* 57 */ "ENOTCONN",
+  /* 58 */ "ESHUTDOWN",
+  /* 59 */ "ETOOMANYREFS",
+  /* 60 */ "ETIMEDOUT",
+  /* 61 */ "ECONNREFUSED",
+  /* 62 */ "ELOOP",
+  /* 63 */ "ENAMETOOLONG",
+  /* 64 */ "EHOSTDOWN",
+  /* 65 */ "EHOSTUNREACH",
+  /* 66 */ "ENOTEMPTY",
+  /* 67 */ "EPROCLIM",
+  /* 68 */ "EUSERS",
+  /* 69 */ "EDQUOT",
+  /* 70 */ "ESTALE",
+  /* 71 */ "EREMOTE",
+  /* 72 */ "EBADRPC",
+  /* 73 */ "ERPCMISMATCH",
+  /* 74 */ "EPROGUNAVAIL",
+  /* 75 */ "EPROGMISMATCH",
+  /* 76 */ "EPROCUNAVAIL",
+  /* 77 */ "ENOLCK",
+  /* 78 */ "ENOSYS",
+  /* 79 */ "EFTYPE",
+  /* 80 */ "EAUTH",
+  /* 81 */ "ENEEDAUTH",
+  /* 81 */ "ELAST",
+};
+
+static char *(netbsd_signal_names[]) = {
+  /* 0 */ 0,
+  /* 1 */ "SIGHUP",
+  /* 2 */ "SIGINT",
+  /* 3 */ "SIGQUIT",
+  /* 4 */ "SIGILL",
+  /* 5 */ "SIGTRAP",
+  /* 6 */ "SIGABRT",
+  /* 7 */ "SIGEMT",
+  /* 8 */ "SIGFPE",
+  /* 9 */ "SIGKILL",
+  /* 10 */ "SIGBUS",
+  /* 11 */ "SIGSEGV",
+  /* 12 */ "SIGSYS",
+  /* 13 */ "SIGPIPE",
+  /* 14 */ "SIGALRM",
+  /* 15 */ "SIGTERM",
+  /* 16 */ "SIGURG",
+  /* 17 */ "SIGSTOP",
+  /* 18 */ "SIGTSTP",
+  /* 19 */ "SIGCONT",
+  /* 20 */ "SIGCHLD",
+  /* 21 */ "SIGTTIN",
+  /* 22 */ "SIGTTOU",
+  /* 23 */ "SIGIO",
+  /* 24 */ "SIGXCPU",
+  /* 25 */ "SIGXFSZ",
+  /* 26 */ "SIGVTALRM",
+  /* 27 */ "SIGPROF",
+  /* 28 */ "SIGWINCH",
+  /* 29 */ "SIGINFO",
+  /* 30 */ "SIGUSR1",
+  /* 31 */ "SIGUSR2",
+};
+
+emulation emul_netbsd = {
+  netbsd_descriptors,
+  sizeof(netbsd_descriptors) / sizeof(netbsd_descriptors[0]),
+  netbsd_error_names,
+  sizeof(netbsd_error_names) / sizeof(netbsd_error_names[0]),
+  netbsd_signal_names,
+  sizeof(netbsd_signal_names) / sizeof(netbsd_signal_names[0]),
+};
+
+#endif /* _EMUL_NETBSD_C_ */
diff --git a/sim/ppc/filter_filename.c b/sim/ppc/filter_filename.c
new file mode 100644 (file)
index 0000000..72923b9
--- /dev/null
@@ -0,0 +1,36 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+    */
+
+#include "basics.h"
+
+/* Shorten traces by eliminating the directory component to filenames.  */
+extern char *
+filter_filename (char *filename)
+{
+  char *p = filename;
+  char *last = filename;
+  int ch;
+
+  while ((ch = *p++) != '\0' && ch != ':')
+    if (ch == '/')
+      last = p;
+
+  return last;
+}
diff --git a/sim/ppc/filter_filename.h b/sim/ppc/filter_filename.h
new file mode 100644 (file)
index 0000000..60cc614
--- /dev/null
@@ -0,0 +1,27 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+    */
+
+#ifndef _FILTER_FILENAME_H
+#define _FILTER_FILENAME_H
+
+/* Remove directory part from filename */
+extern char *
+filter_filename(char *filename);
+#endif
diff --git a/sim/ppc/igen.c b/sim/ppc/igen.c
new file mode 100644 (file)
index 0000000..78c1494
--- /dev/null
@@ -0,0 +1,2834 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+    */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "misc.h"
+#include "lf.h"
+#include "table.h"
+
+
+/****************************************************************/
+
+enum {
+  insn_size = 32,
+};
+
+int idecode_expand_semantics = 0;
+int idecode_cache = 0;
+int number_lines = 1;
+
+
+/****************************************************************/
+
+
+char *cache_idecode_formal = "cpu *processor,\n instruction_word instruction,\n unsigned_word cia,\n idecode_cache *cache_entry";
+char *cache_idecode_actual = "processor, instruction, cia, cache_entry";
+
+char *cache_semantic_formal = "cpu *processor,\n idecode_cache *cache_entry,\n unsigned_word cia";
+char *cache_semantic_actual = "processor, entry, cia";
+
+char *semantic_formal = "cpu *processor,\n instruction_word instruction,\n unsigned_word cia";
+char *semantic_actual = "processor, instruction, cia";
+
+char *semantic_local = "unsigned_word nia = cia + 4;";
+
+
+/****************************************************************/
+
+
+typedef struct _filter filter;
+struct _filter {
+  char *flag;
+  filter *next;
+};
+filter *filters = NULL;
+
+
+/****************************************************************/
+
+
+typedef struct _cache_rules cache_rules;
+struct _cache_rules {
+  int valid;
+  char *old_name;
+  char *new_name;
+  char *type;
+  char *expression;
+  cache_rules *next;
+};
+cache_rules *cache_table;
+
+
+enum {
+  ca_valid,
+  ca_old_name,
+  ca_new_name,
+  ca_type,
+  ca_expression,
+  nr_cache_rule_fields,
+};
+
+static cache_rules *
+load_cache_rules(char *file_name)
+{
+  table *file = table_open(file_name, nr_cache_rule_fields);
+  table_entry *entry;
+  cache_rules *table = NULL;
+  cache_rules **curr_rule = &table;
+  while ((entry = table_entry_read(file)) != NULL) {
+    cache_rules *new_rule = ZALLOC(cache_rules);
+    new_rule->valid = a2i(entry->fields[ca_valid]);
+    new_rule->old_name = entry->fields[ca_old_name];
+    new_rule->new_name = entry->fields[ca_new_name];
+    new_rule->type = (strlen(entry->fields[ca_type])
+                     ? entry->fields[ca_type]
+                     : NULL);
+    new_rule->expression = (strlen(entry->fields[ca_expression]) > 0
+                           ? entry->fields[ca_expression]
+                           : NULL);
+    *curr_rule = new_rule;
+    curr_rule = &new_rule->next;
+  }
+  return table;
+}
+
+
+
+static void
+dump_cache_rule(cache_rules* rule,
+               int indent)
+{
+  dumpf(indent, "((cache_rules*)0x%x\n", rule);
+  dumpf(indent, " (valid %d)\n", rule->valid);
+  dumpf(indent, " (old_name \"%s\")\n", rule->old_name);
+  dumpf(indent, " (new_name \"%s\")\n", rule->new_name);
+  dumpf(indent, " (type \"%s\")\n", rule->type);
+  dumpf(indent, " (expression \"%s\")\n", rule->expression);
+  dumpf(indent, " (next 0x%x)\n", rule->next);
+  dumpf(indent, " )\n");
+}
+
+
+static void
+dump_cache_rules(cache_rules* rule, int indent)
+{
+  while (rule) {
+    dump_cache_rule(rule, indent);
+    rule = rule->next;
+  }
+}
+
+
+/****************************************************************/
+
+
+typedef struct _opcode_rules opcode_rules;
+struct _opcode_rules {
+  int first;
+  int last;
+  int force_first;
+  int force_last;
+  int force_slash;
+  char *force_expansion;
+  int use_switch;
+  unsigned special_mask;
+  unsigned special_value;
+  unsigned special_rule;
+  opcode_rules *next;
+};
+opcode_rules *opcode_table;
+
+
+enum {
+  op_first,
+  op_last,
+  op_force_first,
+  op_force_last,
+  op_force_slash,
+  op_force_expansion,
+  op_use_switch,
+  op_special_mask,
+  op_special_value,
+  op_special_rule,
+  nr_opcode_fields,
+};
+
+
+static opcode_rules *
+load_opcode_rules(char *file_name)
+{
+  table *file = table_open(file_name, nr_opcode_fields);
+  table_entry *entry;
+  opcode_rules *table = NULL;
+  opcode_rules **curr_rule = &table;
+  while ((entry = table_entry_read(file)) != NULL) {
+    opcode_rules *new_rule = ZALLOC(opcode_rules);
+    new_rule->first = a2i(entry->fields[op_first]);
+    new_rule->last = a2i(entry->fields[op_last]);
+    new_rule->force_first = a2i(entry->fields[op_force_first]);
+    new_rule->force_last = a2i(entry->fields[op_force_last]);
+    new_rule->force_slash = a2i(entry->fields[op_force_slash]);
+    new_rule->force_expansion = entry->fields[op_force_expansion];
+    new_rule->use_switch = a2i(entry->fields[op_use_switch]);
+    new_rule->special_mask = a2i(entry->fields[op_special_mask]);
+    new_rule->special_value = a2i(entry->fields[op_special_value]);
+    new_rule->special_rule = a2i(entry->fields[op_special_rule]);
+    *curr_rule = new_rule;
+    curr_rule = &new_rule->next;
+  }
+  return table;
+}
+
+  
+static void
+dump_opcode_rule(opcode_rules *rule,
+                int indent)
+{
+  dumpf(indent, "((opcode_rules*)%p\n", rule);
+  if (rule) {
+    dumpf(indent, " (first %d)\n", rule->first);
+    dumpf(indent, " (last %d)\n", rule->last);
+    dumpf(indent, " (force_first %d)\n", rule->force_first);
+    dumpf(indent, " (force_last %d)\n", rule->force_last);
+    dumpf(indent, " (force_slash %d)\n", rule->force_slash);
+    dumpf(indent, " (force_expansion \"%s\")\n", rule->force_expansion);
+    dumpf(indent, " (use_switch %d)\n", rule->use_switch);
+    dumpf(indent, " (special_mask 0x%x)\n", rule->special_mask);
+    dumpf(indent, " (special_value 0x%x)\n", rule->special_value);
+    dumpf(indent, " (special_rule 0x%x)\n", rule->special_rule);
+    dumpf(indent, " (next 0x%x)\n", rule->next);
+  }
+  dumpf(indent, " )\n");
+}
+
+
+static void
+dump_opcode_rules(opcode_rules *rule,
+                 int indent)
+{
+  while (rule) {
+    dump_opcode_rule(rule, indent);
+    rule = rule->next;
+  }
+}
+
+
+/****************************************************************/
+
+typedef struct _insn_field insn_field;
+struct _insn_field {
+  int first;
+  int last;
+  int width;
+  int is_int;
+  int is_slash;
+  int is_string;
+  int val_int;
+  char *pos_string;
+  char *val_string;
+  insn_field *next;
+  insn_field *prev;
+};
+
+typedef struct _insn_fields insn_fields;
+struct _insn_fields {
+  insn_field *bits[insn_size];
+  insn_field *first;
+  insn_field *last;
+  unsigned value;
+};
+
+static insn_fields *
+parse_insn_format(table_entry *entry,
+                 char *format)
+{
+  char *chp;
+  insn_fields *fields = ZALLOC(insn_fields);
+
+  /* create a leading sentinal */
+  fields->first = ZALLOC(insn_field);
+  fields->first->first = -1;
+  fields->first->last = -1;
+  fields->first->width = 0;
+
+  /* and a trailing sentinal */
+  fields->last = ZALLOC(insn_field);
+  fields->last->first = insn_size;
+  fields->last->last = insn_size;
+  fields->last->width = 0;
+
+  /* link them together */
+  fields->first->next = fields->last;
+  fields->last->prev = fields->first;
+
+  /* now work through the formats */
+  chp = format;
+
+  while (*chp != '\0') {
+    char *start_pos;
+    char *start_val;
+    int strlen_val;
+    int strlen_pos;
+    insn_field *new_field;
+
+    /* sanity check */
+    if (!isdigit(*chp)) {
+      error("%s:%d: missing position field at `%s'\n",
+           entry->file_name, entry->line_nr, chp);
+    }
+
+    /* break out the bit position */
+    start_pos = chp;
+    while (isdigit(*chp))
+      chp++;
+    strlen_pos = chp - start_pos;
+    if (*chp == '.' && strlen_pos > 0)
+      chp++;
+    else {
+      error("%s:%d: missing field value at %s\n",
+           entry->file_name, entry->line_nr, chp);
+      break;
+    }
+
+    /* break out the value */
+    start_val = chp;
+    while ((*start_val == '/' && *chp == '/')
+          || (isdigit(*start_val) && isdigit(*chp))
+          || (isalpha(*start_val) && (isalnum(*chp) || *chp == '_')))
+      chp++;
+    strlen_val = chp - start_val;
+    if (*chp == ',')
+      chp++;
+    else if (*chp != '\0' || strlen_val == 0) {
+      error("%s:%d: missing field terminator at %s\n",
+           entry->file_name, entry->line_nr, chp);
+      break;
+    }
+
+    /* create a new field and insert it */
+    new_field = ZALLOC(insn_field);
+    new_field->next = fields->last;
+    new_field->prev = fields->last->prev;
+    new_field->next->prev = new_field;
+    new_field->prev->next = new_field;
+
+    /* the value */
+    new_field->val_string = (char*)zalloc(strlen_val+1);
+    strncpy(new_field->val_string, start_val, strlen_val);
+    if (isdigit(*new_field->val_string)) {
+      new_field->val_int = a2i(new_field->val_string);
+      new_field->is_int = 1;
+    }
+    else if (new_field->val_string[0] == '/') {
+      new_field->is_slash = 1;
+    }
+    else {
+      new_field->is_string = 1;
+    }
+    
+    /* the pos */
+    new_field->pos_string = (char*)zalloc(strlen_pos+1);
+    strncpy(new_field->pos_string, start_pos, strlen_pos);
+    new_field->first = a2i(new_field->pos_string);
+    new_field->last = new_field->next->first - 1; /* guess */
+    new_field->width = new_field->last - new_field->first + 1; /* guess */
+    new_field->prev->last = new_field->first-1; /*fix*/
+    new_field->prev->width = new_field->first - new_field->prev->first; /*fix*/
+  }
+
+  /* fiddle first/last so that the sentinals `disapear' */
+  ASSERT(fields->first->last < 0);
+  ASSERT(fields->last->first >= insn_size);
+  fields->first = fields->first->next;
+  fields->last = fields->last->prev;
+
+  /* now go over this again, pointing each bit position at a field
+     record */
+  {
+    int i;
+    insn_field *field;
+    field = fields->first;
+    for (i = 0; i < insn_size; i++) {
+      while (field->last < i)
+       field = field->next;
+      fields->bits[i] = field;
+    }
+  }
+
+  /* go over each of the fields, and compute a `value' for the insn */
+  {
+    insn_field *field;
+    fields->value = 0;
+    for (field = fields->first;
+        field->last < insn_size;
+        field = field->next) {
+      fields->value <<= field->width;
+      if (field->is_int)
+       fields->value |= field->val_int;
+    }
+  }
+  return fields;
+}
+
+
+typedef enum {
+  field_constant_int = 1,
+  field_constant_slash = 2,
+  field_constant_string = 3
+} constant_field_types;
+
+
+static int
+insn_field_is_constant(insn_field *field,
+                      opcode_rules *rule)
+{
+  /* field is an integer */
+  if (field->is_int)
+    return field_constant_int;
+  /* field is `/' and treating that as a constant */
+  if (field->is_slash && rule->force_slash)
+    return field_constant_slash;
+  /* field, though variable is on the list */
+  if (field->is_string && rule->force_expansion != NULL) {
+    char *forced_fields = rule->force_expansion;
+    while (*forced_fields != '\0') {
+      int field_len;
+      char *end = strchr(forced_fields, ',');
+      if (end == NULL)
+       field_len = strlen(forced_fields);
+      else
+       field_len = end-forced_fields;
+      if (strncmp(forced_fields, field->val_string, field_len) == 0
+         && field->val_string[field_len] == '\0')
+       return field_constant_string;
+      forced_fields += field_len;
+      if (*forced_fields == ',')
+       forced_fields++;
+    }
+  }
+  return 0;
+}
+
+
+static void
+dump_insn_field(insn_field *field,
+               int indent)
+{
+
+  printf("(insn_field*)0x%x\n", (unsigned)field);
+
+  dumpf(indent, "(first %d)\n", field->first);
+
+  dumpf(indent, "(last %d)\n", field->last);
+
+  dumpf(indent, "(width %d)\n", field->width);
+
+  if (field->is_int)
+    dumpf(indent, "(is_int %d)\n", field->val_int);
+
+  if (field->is_slash)
+    dumpf(indent, "(is_slash)\n");
+
+  if (field->is_string)
+    dumpf(indent, "(is_string `%s')\n", field->val_string);
+  
+  dumpf(indent, "(next 0x%x)\n", field->next);
+  
+  dumpf(indent, "(prev 0x%x)\n", field->prev);
+  
+
+}
+
+static void
+dump_insn_fields(insn_fields *fields,
+                int indent)
+{
+  int i;
+
+  printf("(insn_fields*)%p\n", fields);
+
+  dumpf(indent, "(first 0x%x)\n", fields->first);
+  dumpf(indent, "(last 0x%x)\n", fields->last);
+
+  dumpf(indent, "(value 0x%x)\n", fields->value);
+
+  for (i = 0; i < insn_size; i++) {
+    dumpf(indent, "(bits[%d] ", i, fields->bits[i]);
+    dump_insn_field(fields->bits[i], indent+1);
+    dumpf(indent, " )\n");
+  }
+
+}
+
+
+/****************************************************************/
+
+typedef struct _opcode_field opcode_field;
+struct _opcode_field {
+  int first;
+  int last;
+  int is_boolean;
+  opcode_field *parent;
+};
+
+static opcode_field *
+opcode_field_new()
+{
+  opcode_field *new_field = (opcode_field*)zalloc(sizeof(opcode_field));
+  ASSERT(new_field != NULL);
+  new_field->first = insn_size;
+  new_field->last = -1;
+  return new_field;
+}
+
+static void
+dump_opcode_field(opcode_field *field, int indent, int levels)
+{
+  printf("(opcode_field*)%p\n", field);
+  if (levels && field != NULL) {
+    dumpf(indent, "(first %d)\n", field->first);
+    dumpf(indent, "(last %d)\n", field->last);
+    dumpf(indent, "(is_boolean %d)\n", field->is_boolean);
+    dumpf(indent, "(parent ");
+    dump_opcode_field(field->parent, indent, levels-1);
+  }
+}
+
+
+/****************************************************************/
+
+typedef struct _insn_bits insn_bits;
+struct _insn_bits {
+  int is_expanded;
+  int value;
+  insn_field *field;
+  opcode_field *opcode;
+  insn_bits *last;
+};
+
+
+static void
+dump_insn_bits(insn_bits *bits, int indent, int levels)
+{
+  printf("(insn_bits*)%p\n", bits);
+
+  if (levels && bits != NULL) {
+    dumpf(indent, "(value %d)\n", bits->value);
+    dumpf(indent, "(opcode ");
+    dump_opcode_field(bits->opcode, indent+1, 0);
+    dumpf(indent, " )\n");
+    dumpf(indent, "(field ");
+    dump_insn_field(bits->field, indent+1);
+    dumpf(indent, " )\n");
+    dumpf(indent, "(last ");
+    dump_insn_bits(bits->last, indent+1, levels-1);
+  }
+}
+
+
+/****************************************************************/
+
+
+typedef enum {
+  insn_format,
+  insn_form,
+  insn_flags,
+  insn_nmemonic,
+  insn_name,
+  insn_comment,
+  nr_insn_table_fields,
+} insn_table_fields;
+char *insn_field_name[nr_insn_table_fields] = {
+  "format", "form", "flags", "nmemonic", "name", "comments"
+};
+
+typedef enum {
+  function_type = insn_format,
+  function_name = insn_name,
+  function_param = insn_comment,
+} function_table_fields;
+
+
+typedef struct _insn insn;
+struct _insn {
+  table_entry *file_entry;
+  insn_fields *fields;
+  insn *next;
+};
+
+typedef struct _insn_table insn_table;
+struct _insn_table {
+  int opcode_nr;
+  insn_bits *expanded_bits;
+  int nr_insn;
+  insn *insns;
+  insn *functions;
+  opcode_rules *opcode_rule;
+  opcode_field *opcode;
+  int nr_entries;
+  insn_table *entries;
+  insn_table *sibling;
+  insn_table *parent;
+};
+
+
+
+static void
+insn_table_insert_function(insn_table *table,
+                          table_entry *file_entry)
+{
+  insn **ptr_to_cur_function = &table->functions;
+
+  /* create a new function */
+  insn *new_function = ZALLOC(insn);
+  new_function->file_entry = file_entry;
+
+  /* append it to the end of the function list */
+  while (*ptr_to_cur_function != NULL) {
+    ptr_to_cur_function = &(*ptr_to_cur_function)->next;
+  }
+  *ptr_to_cur_function = new_function;
+}
+
+
+static void
+insn_table_insert_insn(insn_table *table,
+                      table_entry *file_entry,
+                      insn_fields *fields)
+{
+  insn **ptr_to_cur_insn = &table->insns;
+  insn *cur_insn = *ptr_to_cur_insn;
+
+  /* create a new instruction */
+  insn *new_insn = ZALLOC(insn);
+  new_insn->file_entry = file_entry;
+  new_insn->fields = fields;
+
+  /* insert it according to the order of the fields */
+  while (cur_insn != NULL
+        && new_insn->fields->value >= cur_insn->fields->value) {
+    ptr_to_cur_insn = &cur_insn->next;
+    cur_insn = *ptr_to_cur_insn;
+  }
+
+  new_insn->next = cur_insn;
+  *ptr_to_cur_insn = new_insn;
+
+  table->nr_insn++;
+}
+
+
+static opcode_field *
+insn_table_find_opcode_field(insn *insns,
+                            opcode_rules *rule,
+                            int string_only)
+{
+  opcode_field *curr_opcode = opcode_field_new();
+  insn *entry;
+
+  ASSERT(rule);
+
+  for (entry = insns; entry != NULL; entry = entry->next) {
+    insn_fields *fields = entry->fields;
+    opcode_field new_opcode;
+
+    /* find a start point for the opcode field */
+    new_opcode.first = rule->first;
+    while (new_opcode.first <= rule->last
+          && (!string_only
+              || insn_field_is_constant(fields->bits[new_opcode.first],
+                                        rule) != field_constant_string)
+          && (string_only
+              || !insn_field_is_constant(fields->bits[new_opcode.first],
+                                         rule)))
+      new_opcode.first = fields->bits[new_opcode.first]->last + 1;
+    ASSERT(new_opcode.first > rule->last
+          || (string_only
+              && insn_field_is_constant(fields->bits[new_opcode.first],
+                                        rule) == field_constant_string)
+          || (!string_only
+              && insn_field_is_constant(fields->bits[new_opcode.first],
+                                        rule)));
+  
+    /* find the end point for the opcode field */
+    new_opcode.last = rule->last;
+    while (new_opcode.last >= rule->first
+          && (!string_only
+              || insn_field_is_constant(fields->bits[new_opcode.last],
+                                        rule) != field_constant_string)
+          && (string_only
+              || !insn_field_is_constant(fields->bits[new_opcode.last],
+                                         rule)))
+      new_opcode.last = fields->bits[new_opcode.last]->first - 1;
+    ASSERT(new_opcode.last < rule->first
+          || (string_only
+              && insn_field_is_constant(fields->bits[new_opcode.last],
+                                        rule) == field_constant_string)
+          || (!string_only
+              && insn_field_is_constant(fields->bits[new_opcode.last],
+                                        rule)));
+
+    /* now see if our current opcode needs expanding */
+    if (new_opcode.first <= rule->last
+       && curr_opcode->first > new_opcode.first)
+      curr_opcode->first = new_opcode.first;
+    if (new_opcode.last >= rule->first
+       && curr_opcode->last < new_opcode.last)
+      curr_opcode->last = new_opcode.last;
+    
+  }
+
+  /* was any thing interesting found? */
+  if (curr_opcode->first > rule->last) {
+    ASSERT(curr_opcode->last < rule->first);
+    return NULL;
+  }
+  ASSERT(curr_opcode->last >= rule->first);
+  ASSERT(curr_opcode->first <= rule->last);
+
+  /* if something was found, check it includes the forced field range */
+  if (!string_only
+      && curr_opcode->first > rule->force_first) {
+    curr_opcode->first = rule->force_first;
+  }
+  if (!string_only
+      && curr_opcode->last < rule->force_last) {
+    curr_opcode->last = rule->force_last;
+  }
+  /* handle special case elminating any need to do shift after mask */
+  if (string_only
+      && rule->force_last == insn_size-1) {
+    curr_opcode->last = insn_size-1;
+  }
+
+  /* handle any special cases */
+  switch (rule->special_rule) {
+  case 0: /* let the above apply */
+    break;
+  case 1: /* expand a limited nr of bits, ignoring the rest */
+    curr_opcode->first = rule->force_first;
+    curr_opcode->last = rule->force_last;
+    break;
+  case 2: /* boolean field */
+    curr_opcode->is_boolean = 1;
+    break;
+  }
+
+  return curr_opcode;
+}
+
+
+static void
+insn_table_insert_expanded(insn_table *table,
+                          insn *old_insn,
+                          int new_opcode_nr,
+                          insn_bits *new_bits)
+{
+  insn_table **ptr_to_cur_entry = &table->entries;
+  insn_table *cur_entry = *ptr_to_cur_entry;
+
+  /* find the new table for this entry */
+  while (cur_entry != NULL
+        && cur_entry->opcode_nr < new_opcode_nr) {
+    ptr_to_cur_entry = &cur_entry->sibling;
+    cur_entry = *ptr_to_cur_entry;
+  }
+
+  if (cur_entry == NULL || cur_entry->opcode_nr != new_opcode_nr) {
+    insn_table *new_entry = ZALLOC(insn_table);
+    new_entry->opcode_nr = new_opcode_nr;
+    new_entry->expanded_bits = new_bits;
+    new_entry->opcode_rule = table->opcode_rule->next;
+    new_entry->sibling = cur_entry;
+    new_entry->parent = table;
+    *ptr_to_cur_entry = new_entry;
+    cur_entry = new_entry;
+    table->nr_entries++;
+  }
+  /* ASSERT new_bits == cur_entry bits */
+  ASSERT(cur_entry != NULL && cur_entry->opcode_nr == new_opcode_nr);
+  insn_table_insert_insn(cur_entry,
+                        old_insn->file_entry,
+                        old_insn->fields);
+}
+
+static void
+insn_table_expand_opcode(insn_table *table,
+                        insn *instruction,
+                        int field_nr,
+                        int opcode_nr,
+                        insn_bits *bits)
+{
+
+  if (field_nr > table->opcode->last) {
+    insn_table_insert_expanded(table, instruction, opcode_nr, bits);
+  }
+  else {
+    insn_field *field = instruction->fields->bits[field_nr];
+    if (field->is_int || field->is_slash) {
+      ASSERT(field->first >= table->opcode->first
+            && field->last <= table->opcode->last);
+      insn_table_expand_opcode(table, instruction, field->last+1,
+                              ((opcode_nr << field->width) + field->val_int),
+                              bits);
+    }
+    else {
+      int val;
+      int last_pos = ((field->last < table->opcode->last)
+                       ? field->last : table->opcode->last);
+      int first_pos = ((field->first > table->opcode->first)
+                        ? field->first : table->opcode->first);
+      int width = last_pos - first_pos + 1;
+      int last_val = (table->opcode->is_boolean
+                     ? 2 : (1 << width));
+      for (val = 0; val < last_val; val++) {
+       insn_bits *new_bits = ZALLOC(insn_bits);
+       new_bits->field = field;
+       new_bits->value = val;
+       new_bits->last = bits;
+       new_bits->opcode = table->opcode;
+       insn_table_expand_opcode(table, instruction, last_pos+1,
+                                ((opcode_nr << width) | val),
+                                new_bits);
+      }
+    }
+  }
+}
+
+static void
+insn_table_insert_expanding(insn_table *table,
+                           insn *entry)
+{
+  insn_table_expand_opcode(table,
+                          entry,
+                          table->opcode->first,
+                          0,
+                          table->expanded_bits);
+}
+
+
+static void
+insn_table_expand_insns(insn_table *table)
+{
+
+  ASSERT(table->nr_insn >= 1);
+
+  /* determine a valid opcode */
+  while (table->opcode_rule) {
+    /* specials only for single instructions */
+    if ((table->nr_insn > 1
+        && table->opcode_rule->special_mask == 0
+        && table->opcode_rule->special_rule == 0)
+       || (table->nr_insn == 1
+           && table->opcode_rule->special_mask != 0
+           && ((table->insns->fields->value
+                & table->opcode_rule->special_mask)
+               == table->opcode_rule->special_value))
+       || (idecode_expand_semantics
+           && table->opcode_rule->special_mask == 0
+           && table->opcode_rule->special_rule == 0))
+      table->opcode =
+       insn_table_find_opcode_field(table->insns,
+                                    table->opcode_rule,
+                                    table->nr_insn == 1/*string*/
+                                    );
+    if (table->opcode != NULL)
+      break;
+    table->opcode_rule = table->opcode_rule->next;
+  }
+
+  /* did we find anything */
+  if (table->opcode == NULL) {
+    return;
+  }
+  ASSERT(table->opcode != NULL);
+
+  /* back link what we found to its parent */
+  if (table->parent != NULL) {
+    ASSERT(table->parent->opcode != NULL);
+    table->opcode->parent = table->parent->opcode;
+  }
+
+  /* expand the raw instructions according to the opcode */
+  {
+    insn *entry;
+    for (entry = table->insns; entry != NULL; entry = entry->next) {
+      insn_table_insert_expanding(table, entry);
+    }
+  }
+
+  /* and do the same for the sub entries */
+  {
+    insn_table *entry;
+    for (entry = table->entries; entry != NULL; entry =  entry->sibling) {
+      insn_table_expand_insns(entry);
+    }
+  }
+}
+
+
+
+static insn_table *
+insn_table_load_insns(char *file_name)
+{
+  table *file = table_open(file_name, nr_insn_table_fields);
+  insn_table *table = ZALLOC(insn_table);
+  table_entry *file_entry;
+  table->opcode_rule = opcode_table;
+
+  while ((file_entry = table_entry_read(file)) != NULL) {
+    if (it_is("function", file_entry->fields[insn_flags])
+       || it_is("internal", file_entry->fields[insn_flags])) {
+      insn_table_insert_function(table, file_entry);
+    }
+    else {
+      insn_fields *fields;
+      /* skip instructions that aren't relevant to the mode */
+      filter *filt = filters;
+      while (filt != NULL) {
+       if (it_is(filt->flag, file_entry->fields[insn_flags]))
+         break;
+       filt = filt->next;
+      }
+      if (filt == NULL) {
+       /* create/insert the new instruction */
+       fields = parse_insn_format(file_entry,
+                                  file_entry->fields[insn_format]);
+       insn_table_insert_insn(table, file_entry, fields);
+      }
+    }
+  }
+  return table;
+}
+
+
+static void
+dump_insn(insn *entry, int indent, int levels)
+{
+  printf("(insn*)%p\n", entry);
+
+  if (levels && entry != NULL) {
+
+    dumpf(indent, "(file_entry ");
+    dump_table_entry(entry->file_entry, indent+1);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(fields ");
+    dump_insn_fields(entry->fields, indent+1);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(next ");
+    dump_insn(entry->next, indent+1, levels-1);
+    dumpf(indent, " )\n");
+
+  }
+
+}
+
+
+static void
+dump_insn_table(insn_table *table,
+               int indent, int levels)
+{
+
+  printf("(insn_table*)%p\n", table);
+
+  if (levels && table != NULL) {
+
+    dumpf(indent, "(opcode_nr %d)\n", table->opcode_nr);
+
+    dumpf(indent, "(expanded_bits ");
+    dump_insn_bits(table->expanded_bits, indent+1, -1);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(int nr_insn %d)\n", table->nr_insn);
+
+    dumpf(indent, "(insns ");
+    dump_insn(table->insns, indent+1, table->nr_insn);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(opcode_rule ");
+    dump_opcode_rule(table->opcode_rule, indent+1);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(opcode ");
+    dump_opcode_field(table->opcode, indent+1, 1);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(nr_entries %d)\n", table->entries);
+    dumpf(indent, "(entries ");
+    dump_insn_table(table->entries, indent+1, table->nr_entries);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(sibling ", table->sibling);
+    dump_insn_table(table->sibling, indent+1, levels-1);
+    dumpf(indent, " )\n");
+
+    dumpf(indent, "(parent ", table->parent);
+    dump_insn_table(table->parent, indent+1, 0);
+    dumpf(indent, " )\n");
+
+  }
+}
+
+
+/****************************************************************/
+
+
+static void
+lf_print_insn_bits(lf *file, insn_bits *bits)
+{
+  if (bits == NULL)
+    return;
+  lf_print_insn_bits(file, bits->last);
+  lf_putchr(file, '_');
+  lf_putstr(file, bits->field->val_string);
+  if (!bits->opcode->is_boolean || bits->value == 0) {
+    if (bits->opcode->last < bits->field->last)
+      lf_putint(file, bits->value << (bits->field->last - bits->opcode->last));
+    else
+      lf_putint(file, bits->value);
+  }
+}
+
+static void
+lf_print_opcodes(lf *file,
+                insn_table *table)
+{
+  if (table != NULL) {
+    while (1) {
+      lf_printf(file, "_%d_%d",
+               table->opcode->first,
+               table->opcode->last);
+      if (table->parent == NULL) break;
+      lf_printf(file, "__%d", table->opcode_nr);
+      table = table->parent;
+    }
+  }
+}
+
+static void
+lf_print_table_name(lf *file,
+                   insn_table *table)
+{
+  lf_printf(file, "idecode_table");
+  lf_print_opcodes(file, table);
+}
+
+
+
+typedef enum {
+  function_name_prefix_semantics,
+  function_name_prefix_idecode,
+  function_name_prefix_itable,
+  function_name_prefix_none
+} lf_function_name_prefixes;
+
+static void
+lf_print_function_name(lf *file,
+                      char *basename,
+                      insn_bits *expanded_bits,
+                      lf_function_name_prefixes prefix)
+{
+
+  /* the prefix */
+  switch (prefix) {
+  case function_name_prefix_semantics:
+    lf_putstr(file, "semantic_");
+    break;
+  case function_name_prefix_idecode:
+    lf_printf(file, "idecode_");
+    break;
+  case function_name_prefix_itable:
+    lf_putstr(file, "itable_");
+    break;
+  default:
+    break;
+  }
+
+  /* the function name */
+  {
+    char *pos;
+    for (pos = basename;
+        *pos != '\0';
+        pos++) {
+      switch (*pos) {
+      case '/':
+      case '-':
+       break;
+      case ' ':
+       lf_putchr(file, '_');
+       break;
+      default:
+       lf_putchr(file, *pos);
+       break;
+      }
+    }
+  }
+
+  /* the suffix */
+  if (idecode_expand_semantics)
+    lf_print_insn_bits(file, expanded_bits);
+}
+
+
+static void
+lf_print_idecode_table(lf *file,
+                      insn_table *entry)
+{
+  int can_assume_leaf;
+  opcode_rules *opcode_rule;
+
+  /* have a look at the rule table, if all table rules follow all
+     switch rules, I can assume that all end points are leaves */
+  opcode_rule = opcode_table;
+  while (opcode_rule != NULL
+        && opcode_rule->use_switch)
+    opcode_rule = opcode_rule->next;
+  while (opcode_rule != NULL
+        && opcode_rule->use_switch
+        && opcode_rule->special_rule)
+    opcode_rule = opcode_rule->next;
+  can_assume_leaf = opcode_rule == NULL;
+
+  lf_printf(file, "{\n");
+  lf_indent(file, +2);
+  {
+    lf_printf(file, "idecode_table_entry *table = ");
+    lf_print_table_name(file, entry);
+    lf_printf(file, ";\n");
+    lf_printf(file, "int opcode = EXTRACTED32(instruction, %d, %d);\n",
+             entry->opcode->first, entry->opcode->last);
+    lf_printf(file, "idecode_table_entry *table_entry = table + opcode;\n");
+    lf_printf(file, "while (1) {\n");
+    lf_indent(file, +2);
+    {
+      lf_printf(file, "while (table_entry->mask != 0) {\n");
+      lf_indent(file, +2);
+      {
+       lf_printf(file, "table = ((idecode_table_entry*)\n");
+       lf_printf(file, "         table_entry->function_or_table);\n");
+       lf_printf(file, "opcode = ((instruction & table_entry->mask)\n");
+       lf_printf(file, "          >> table_entry->shift);\n");
+       lf_printf(file, "table_entry = table + opcode;\n");
+      }
+      lf_indent(file, -2);
+      lf_printf(file, "}\n");
+      if (!idecode_cache && can_assume_leaf) {
+       lf_printf(file, "return (((idecode_semantic*)\n");
+       lf_printf(file, "         table_entry->function_or_table)\n");
+       lf_printf(file, "        (%s));\n", semantic_actual);
+      }
+      else if (!idecode_cache && !can_assume_leaf) {
+       lf_printf(file, "if (table_entry->shift == 0)");
+       lf_printf(file, "  return (((idecode_semantic*)\n");
+       lf_printf(file, "           table_entry->function_or_table)\n");
+       lf_printf(file, "          (%s));\n", semantic_actual);
+      }
+      else {
+       lf_printf(file, "if (table_entry->shift == 0)\n");
+       lf_printf(file, "  return (((idecode_crack*)\n");
+       lf_printf(file, "           table_entry->function_or_table)\n");
+       lf_printf(file, "          (%s));\n", cache_idecode_actual);
+      }
+      if (!can_assume_leaf) {
+       lf_printf(file, "opcode = (instruction & table_entry->shift) != 0;\n");
+       lf_printf(file, "table = ((idecode_table_entry*)\n");
+       lf_printf(file, "         table_entry->function_or_table);\n");
+       lf_printf(file, "table_entry = table + opcode;\n");
+      }
+    }
+    lf_indent(file, -2);
+    lf_printf(file, "}\n");
+  }
+  lf_indent(file, -2);
+  lf_printf(file, "}\n");
+}
+
+
+static void
+lf_print_my_prefix(lf *file,
+                  table_entry *file_entry,
+                  int idecode)
+{
+  lf_printf(file, "const char *const my_prefix = \n");
+  lf_printf(file, "  \"%s:%s:%s:%d\";\n",
+           filter_filename (file_entry->file_name),
+           (idecode ? "idecode" : "semantics"),
+           file_entry->fields[insn_name],
+           file_entry->line_nr);
+}
+
+
+static void
+lf_print_ptrace(lf *file,
+               int idecode)
+{
+  lf_printf(file, "\n");
+  lf_printf(file, "ITRACE(trace_%s, (\"\\n\"));\n",
+           (idecode ? "idecode" : "semantics"));
+}
+
+
+/****************************************************************/
+
+typedef void leaf_handler
+(insn_table *entry,
+ void *data,
+ int depth);
+typedef void padding_handler
+(insn_table *table,
+ void *data,
+ int depth,
+ int opcode_nr);
+
+
+static void
+insn_table_traverse_tree(insn_table *table,
+                        void *data,
+                        int depth,
+                        leaf_handler *start,
+                        leaf_handler *leaf,
+                        leaf_handler *end,
+                        padding_handler *padding)
+{
+  insn_table *entry;
+  int entry_nr;
+  
+  ASSERT(table != NULL
+        && table->opcode != NULL
+        && table->nr_entries > 0
+        && table->entries != 0);
+
+  if (start != NULL && depth >= 0)
+    start(table, data, depth);
+
+  for (entry_nr = 0, entry = table->entries;
+       entry_nr < (table->opcode->is_boolean
+                  ? 2
+                  : (1 << (table->opcode->last - table->opcode->first + 1)));
+       entry_nr ++) {
+    if (entry == NULL
+       || (!table->opcode->is_boolean
+           && entry_nr < entry->opcode_nr)) {
+      if (padding != NULL && depth >= 0)
+       padding(table, data, depth, entry_nr);
+    }
+    else {
+      ASSERT(entry != NULL && (entry->opcode_nr == entry_nr
+                              || table->opcode->is_boolean));
+      if (entry->opcode != NULL && depth != 0) {
+       insn_table_traverse_tree(entry, data, depth+1,
+                                start, leaf, end, padding);
+      }
+      else if (depth >= 0) {
+       if (leaf != NULL)
+         leaf(entry, data, depth);
+      }
+      entry = entry->sibling;
+    }
+  }
+  if (end != NULL && depth >= 0)
+    end(table, data, depth);
+}
+
+
+typedef void function_handler
+(insn_table *table,
+ void *data,
+ table_entry *function);
+
+static void
+insn_table_traverse_function(insn_table *table,
+                            void *data,
+                            function_handler *leaf)
+{
+  insn *function;
+  for (function = table->functions;
+       function != NULL;
+       function = function->next) {
+    leaf(table, data, function->file_entry);
+  }
+}
+
+
+typedef void insn_handler
+(insn_table *table,
+ void *data,
+ insn *instruction);
+
+static void
+insn_table_traverse_insn(insn_table *table,
+                        void *data,
+                        insn_handler *leaf)
+{
+  insn *instruction;
+  for (instruction = table->insns;
+       instruction != NULL;
+       instruction = instruction->next) {
+    leaf(table, data, instruction);
+  }
+}
+
+
+static void
+update_depth(insn_table *entry,
+            void *data,
+            int depth)
+{
+  int *max_depth = (int*)data;
+  if (*max_depth < depth)
+    *max_depth = depth;
+}
+
+
+static int
+insn_table_depth(insn_table *table)
+{
+  int depth = 0;
+  insn_table_traverse_tree(table,
+                          &depth,
+                          1,
+                          NULL, /*start*/
+                          update_depth,
+                          NULL, /*end*/
+                          NULL); /*padding*/
+  return depth;
+}
+
+
+/****************************************************************/
+
+static void
+dump_traverse_start(insn_table *table,
+                   void *data,
+                   int depth)
+{
+  dumpf(depth*2, "(%d\n", table->opcode_nr);
+}
+
+static void
+dump_traverse_leaf(insn_table *entry,
+                  void *data,
+                  int depth)
+{
+  ASSERT(entry->nr_entries == 0
+        && entry->nr_insn == 1
+        && entry->opcode == NULL);
+  dumpf(depth*2, ".%d %s\n", entry->opcode_nr,
+       entry->insns->file_entry->fields[insn_format]);
+}
+
+static void
+dump_traverse_end(insn_table *table,
+                 void *data,
+                 int depth)
+{
+  dumpf(depth*2, ")\n");
+}
+
+static void
+dump_traverse_padding(insn_table *table,
+                     void *data,
+                     int depth,
+                     int opcode_nr)
+{
+  dumpf(depth*2, ".<%d>\n", opcode_nr);
+}
+
+
+static void
+dump_traverse(insn_table *table)
+{
+  insn_table_traverse_tree(table, NULL, 1,
+                          dump_traverse_start,
+                          dump_traverse_leaf,
+                          dump_traverse_end,
+                          dump_traverse_padding);
+}
+
+
+/****************************************************************/
+
+
+static void
+semantics_h_print_function(lf *file,
+                          char *basename,
+                          insn_bits *expanded_bits)
+{
+  lf_printf(file, "\n");
+  lf_printf(file, "INLINE_SEMANTICS unsigned_word ");
+  lf_print_function_name(file,
+                        basename,
+                        expanded_bits,
+                        function_name_prefix_semantics);
+  lf_printf(file, "\n(%s);\n", 
+           (idecode_cache ? cache_semantic_formal : semantic_formal));
+}
+
+
+static void
+semantics_h_leaf(insn_table *entry,
+                void *data,
+                int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(entry->nr_insn == 1);
+  semantics_h_print_function(file,
+                            entry->insns->file_entry->fields[insn_name],
+                            entry->expanded_bits);
+}
+
+static void
+semantics_h_insn(insn_table *entry,
+                void *data,
+                insn *instruction)
+{
+  lf *file = (lf*)data;
+  semantics_h_print_function(file,
+                            instruction->file_entry->fields[insn_name],
+                            NULL);
+}
+
+static void
+semantics_h_function(insn_table *entry,
+                    void *data,
+                    table_entry *function)
+{
+  lf *file = (lf*)data;
+  if (function->fields[function_type] == NULL
+      || function->fields[function_type][0] == '\0') {
+    semantics_h_print_function(file,
+                              function->fields[function_name],
+                              NULL);
+  }
+  else {
+    lf_printf(file, "\n");
+    lf_printf(file, "INLINE_SEMANTICS %s %s\n(%s);\n",
+             function->fields[function_type],
+             function->fields[function_name],
+             function->fields[function_param]);
+  }
+}
+
+
+static void 
+gen_semantics_h(insn_table *table, lf *file)
+{
+
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _SEMANTICS_H_\n");
+  lf_printf(file, "#define _SEMANTICS_H_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef INLINE_SEMANTICS\n");
+  lf_printf(file, "#define INLINE_SEMANTICS\n");
+  lf_printf(file, "#endif\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "\n");
+
+  /* output a declaration for all functions */
+  insn_table_traverse_function(table,
+                              file,
+                              semantics_h_function);
+
+  /* output a declaration for all instructions */
+  if (idecode_expand_semantics)
+    insn_table_traverse_tree(table,
+                            file,
+                            1,
+                            NULL, /* start */
+                            semantics_h_leaf, /* leaf */
+                            NULL, /* end */
+                            NULL); /* padding */
+  else
+    insn_table_traverse_insn(table,
+                            file,
+                            semantics_h_insn);
+
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif /* _SEMANTICS_H_ */\n");
+
+}
+
+/****************************************************************/
+
+typedef struct _icache_tree icache_tree;
+struct _icache_tree {
+  char *name;
+  icache_tree *next;
+  icache_tree *children;
+};
+
+static icache_tree *
+icache_tree_insert(icache_tree *tree,
+                  char *name)
+{
+  icache_tree *new_tree;
+  /* find it */
+  icache_tree **ptr_to_cur_tree = &tree->children;
+  icache_tree *cur_tree = *ptr_to_cur_tree;
+  while (cur_tree != NULL
+        && strcmp(cur_tree->name, name) < 0) {
+    ptr_to_cur_tree = &cur_tree->next;
+    cur_tree = *ptr_to_cur_tree;
+  }
+  ASSERT(cur_tree == NULL
+        || strcmp(cur_tree->name, name) >= 0);
+  /* already in the tree */
+  if (cur_tree != NULL
+      && strcmp(cur_tree->name, name) == 0)
+    return cur_tree;
+  /* missing, insert it */
+  ASSERT(cur_tree == NULL
+        || strcmp(cur_tree->name, name) > 0);
+  new_tree = ZALLOC(icache_tree);
+  new_tree->name = name;
+  new_tree->next = cur_tree;
+  *ptr_to_cur_tree = new_tree;
+  return new_tree;
+}
+
+
+static icache_tree *
+insn_table_cache_fields(insn_table *table)
+{
+  icache_tree *tree = ZALLOC(icache_tree);
+  insn *instruction;
+  for (instruction = table->insns;
+       instruction != NULL;
+       instruction = instruction->next) {
+    insn_field *field;
+    icache_tree *form =
+      icache_tree_insert(tree,
+                        instruction->file_entry->fields[insn_form]);
+    for (field = instruction->fields->first;
+        field != NULL;
+        field = field->next) {
+      if (field->is_string)
+       icache_tree_insert(form, field->val_string);
+    }
+  }
+  return tree;
+}
+
+
+
+static void
+gen_icache_h(icache_tree *tree,
+            lf *file)
+{
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _ICACHE_H_\n");
+  lf_printf(file, "#define _ICACHE_H_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef INLINE_ICACHE\n");
+  lf_printf(file, "#define INLINE_ICACHE\n");
+  lf_printf(file, "#endif\n");
+  lf_printf(file, "\n");
+
+  lf_printf(file, "#define WITH_IDECODE_CACHE_SIZE %d\n",
+           idecode_cache);
+  lf_printf(file, "\n");
+
+  /* create an instruction cache if being used */
+  if (idecode_cache) {
+    icache_tree *form;
+    lf_printf(file, "typedef struct _idecode_cache {\n");
+    lf_printf(file, "  unsigned_word address;\n");
+    lf_printf(file, "  void *semantic;\n");
+    lf_printf(file, "  union {\n");
+    for (form = tree->children;
+        form != NULL;
+        form = form->next) {
+      icache_tree *field;
+      lf_printf(file, "    struct {\n");
+      for (field = form->children;
+          field != NULL;
+          field = field->next) {
+       cache_rules *cache_rule;
+       int found_rule = 0;
+       for (cache_rule = cache_table;
+            cache_rule != NULL;
+            cache_rule = cache_rule->next) {
+         if (strcmp(field->name, cache_rule->old_name) == 0) {
+           found_rule = 1;
+           if (cache_rule->new_name != NULL)
+             lf_printf(file, "      %s %s; /* %s */\n",
+                       (cache_rule->type == NULL
+                        ? "unsigned" 
+                        : cache_rule->type),
+                       cache_rule->new_name,
+                       cache_rule->old_name);
+         }
+       }
+       if (!found_rule)
+         lf_printf(file, "      unsigned %s;\n", field->name);
+      }
+      lf_printf(file, "    } %s;\n", form->name);
+    }
+    lf_printf(file, "  } crack;\n");
+    lf_printf(file, "} idecode_cache;\n");
+  }
+  else {
+    /* alernativly, since no cache, #define the fields to be
+       extractions from the instruction variable */
+    cache_rules *cache_rule;
+    lf_printf(file, "\n");
+    for (cache_rule = cache_table;
+        cache_rule != NULL;
+        cache_rule = cache_rule->next) {
+      if (cache_rule->expression != NULL
+         && strlen(cache_rule->expression) > 0)
+       lf_printf(file, "#define %s %s\n",
+                 cache_rule->new_name, cache_rule->expression);
+    }
+  }
+
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif /* _ICACHE_H_ */\n");
+}
+
+
+
+
+/****************************************************************/
+
+
+static void
+lf_print_c_extraction(lf *file,
+                     insn *instruction,
+                     char *field_name,
+                     char *field_type,
+                     char *field_expression,
+                     insn_field *cur_field,
+                     insn_bits *bits,
+                     int get_value_from_cache,
+                     int put_value_in_cache)
+{
+  ASSERT(field_name != NULL);
+  if (bits != NULL
+      && (!bits->opcode->is_boolean || bits->value == 0)
+      && strcmp(field_name, cur_field->val_string) == 0) {
+    ASSERT(bits->field == cur_field);
+    ASSERT(field_type == NULL);
+    table_entry_lf_c_line_nr(file, instruction->file_entry);
+    lf_printf(file, "const unsigned %s = ",
+             field_name);
+    if (bits->opcode->last < bits->field->last)
+      lf_printf(file, "%d;\n",
+               bits->value << (bits->field->last - bits->opcode->last));
+    else
+      lf_printf(file, "%d;\n", bits->value);
+  }
+  else {
+    /* put the field in the local variable */
+    table_entry_lf_c_line_nr(file, instruction->file_entry);
+    lf_printf(file, "%s const %s = ",
+             field_type == NULL ? "unsigned" : field_type,
+             field_name);
+    /* getting it from the cache */
+    if (get_value_from_cache || put_value_in_cache) {
+      lf_printf(file, "cache_entry->crack.%s.%s",
+               instruction->file_entry->fields[insn_form],
+               field_name);
+      if (put_value_in_cache) /* also put it in the cache? */
+       lf_printf(file, " = ");
+    }
+    if (!get_value_from_cache) {
+      if (strcmp(field_name, cur_field->val_string) == 0)
+       lf_printf(file, "EXTRACTED32(instruction, %d, %d)",
+                 cur_field->first, cur_field->last);
+      else if (field_expression != NULL)
+       lf_printf(file, "%s", field_expression);
+      else
+       lf_printf(file, "eval_%s", field_name);
+    }
+    lf_printf(file, ";\n");
+  }
+}
+
+
+static void
+lf_print_c_extractions(lf *file,
+                      insn *instruction,
+                      insn_bits *expanded_bits,
+                      int get_value_from_cache,
+                      int put_value_in_cache)
+{
+  insn_field *cur_field;
+
+  /* extract instruction fields */
+  lf_printf(file, "/* extraction: %s */\n",
+           instruction->file_entry->fields[insn_format]);
+
+  for (cur_field = instruction->fields->first;
+       cur_field->first < insn_size;
+       cur_field = cur_field->next) {
+    if (cur_field->is_string) {
+      insn_bits *bits;
+      int found_rule = 0;
+      /* find any corresponding value */
+      for (bits = expanded_bits;
+          bits != NULL;
+          bits = bits->last) {
+       if (bits->field == cur_field)
+         break;
+      }
+      /* try the cache rule table for what to do */
+      if (get_value_from_cache || put_value_in_cache) {      
+       cache_rules *cache_rule;
+       for (cache_rule = cache_table;
+            cache_rule != NULL;
+            cache_rule = cache_rule->next) {
+         if (strcmp(cur_field->val_string, cache_rule->old_name) == 0) {
+           found_rule = 1;
+           if (cache_rule->valid > 1 && put_value_in_cache)
+             lf_print_c_extraction(file,
+                                   instruction,
+                                   cache_rule->new_name,
+                                   cache_rule->type,
+                                   cache_rule->expression,
+                                   cur_field,
+                                   bits,
+                                   0,
+                                   0);
+           else if (cache_rule->valid == 1)
+             lf_print_c_extraction(file,
+                                   instruction,
+                                   cache_rule->new_name,
+                                   cache_rule->type,
+                                   cache_rule->expression,
+                                   cur_field,
+                                   bits,
+                                   get_value_from_cache,
+                                   put_value_in_cache);
+         }
+       }
+      }
+      if (found_rule == 0)
+       lf_print_c_extraction(file,
+                             instruction,
+                             cur_field->val_string,
+                             0,
+                             0,
+                             cur_field,
+                             bits,
+                             get_value_from_cache,
+                             put_value_in_cache);
+      /* if any (XXX == 0), output a corresponding test */
+      if (instruction->file_entry->annex != NULL) {
+       char *field_name = cur_field->val_string;
+       char *is_0_ptr = instruction->file_entry->annex;
+       int field_len = strlen(field_name);
+       if (strlen(is_0_ptr) >= (strlen("_is_0") + field_len)) {
+         is_0_ptr += field_len;
+         while ((is_0_ptr = strstr(is_0_ptr, "_is_0")) != NULL) {
+           if (strncmp(is_0_ptr - field_len, field_name, field_len) == 0
+               && !isalpha(is_0_ptr[ - field_len - 1])) {
+             table_entry_lf_c_line_nr(file, instruction->file_entry);
+             lf_printf(file, "const unsigned %s_is_0 = (", field_name);
+             if (bits != NULL)
+               lf_printf(file, "%d", bits->value);
+             else
+               lf_printf(file, "%s", field_name);
+             lf_printf(file, " == 0);\n");
+             break;
+           }
+           is_0_ptr += strlen("_is_0");
+         }
+       }
+      }
+      /* any thing else ... */
+    }
+  }
+  lf_print_lf_c_line_nr(file);
+}
+
+
+static void
+lf_print_idecode_illegal(lf *file)
+{
+  if (idecode_cache)
+    lf_printf(file, "return idecode_illegal(%s);\n", cache_idecode_actual);
+  else
+    lf_printf(file, "return semantic_illegal(%s);\n", semantic_actual);
+}
+
+
+static void
+lf_print_idecode_floating_point_unavailable(lf *file)
+{
+  if (idecode_cache)
+    lf_printf(file, "return idecode_floating_point_unavailable(%s);\n",
+             cache_idecode_actual);
+  else
+    lf_printf(file, "return semantic_floating_point_unavailable(%s);\n",
+             semantic_actual);
+}
+
+
+/* Output code to do any final checks on the decoded instruction.
+   This includes things like verifying any on decoded fields have the
+   correct value and checking that (for floating point) floating point
+   hardware isn't disabled */
+
+static void
+lf_print_c_validate(lf *file,
+                   insn *instruction,
+                   opcode_field *opcodes)
+{
+  /* Validate: unchecked instruction fields
+
+     If any constant fields in the instruction were not checked by the
+     idecode tables, output code to check that they have the correct
+     value here */
+  { 
+    unsigned check_mask = 0;
+    unsigned check_val = 0;
+    insn_field *field;
+    opcode_field *opcode;
+
+    /* form check_mask/check_val containing what needs to be checked
+       in the instruction */
+    for (field = instruction->fields->first;
+        field->first < insn_size;
+        field = field->next) {
+
+      check_mask <<= field->width;
+      check_val <<= field->width;
+
+      /* is it a constant that could need validating? */
+      if (!field->is_int && !field->is_slash)
+       continue;
+
+      /* has it been checked by a table? */
+      for (opcode = opcodes; opcode != NULL; opcode = opcode->parent) {
+       if (field->first >= opcode->first
+           && field->last <= opcode->last)
+         break;
+      }
+      if (opcode != NULL)
+       continue;
+
+      check_mask |= (1 << field->width)-1;
+      check_val |= field->val_int;
+    }
+
+    /* if any bits not checked by opcode tables, output code to check them */
+    if (check_mask) {
+      lf_printf(file, "\n");
+      lf_printf(file, "/* validate: %s */\n",
+               instruction->file_entry->fields[insn_format]);
+      lf_printf(file, "if ((instruction & 0x%x) != 0x%x)\n",
+               check_mask, check_val);
+      lf_indent(file, +2);
+      lf_print_idecode_illegal(file);
+      lf_indent(file, -2);
+    }
+  }
+
+  /* Validate floating point hardware
+
+     If the simulator is being built with out floating point hardware
+     (different to it being disabled in the MSR) then floating point
+     instructions are invalid */
+  {
+    if (it_is("f", instruction->file_entry->fields[insn_flags])) {
+      lf_printf(file, "\n");
+      lf_printf(file, "/* Validate: FP hardware exists */\n");
+      lf_printf(file, "if (CURRENT_FLOATING_POINT != HARD_FLOATING_POINT)\n");
+      lf_indent(file, +2);
+      lf_print_idecode_illegal(file);
+      lf_indent(file, -2);
+    }
+  }
+
+  /* Validate: Floating Point available
+
+     If floating point is not available, we enter a floating point
+     unavailable interrupt into the cache instead of the instruction
+     proper.
+
+     The PowerPC spec requires a CSI after MSR[FP] is changed and when
+     ever a CSI occures we flush the instruction cache. */
+
+  {
+    if (it_is("f", instruction->file_entry->fields[insn_flags])) {
+      lf_printf(file, "\n");
+      lf_printf(file, "/* Validate: FP available according to MSR[FP] */\n");
+      lf_printf(file, "if (!IS_FP_AVAILABLE(processor))\n");
+      lf_indent(file, +2);
+      lf_print_idecode_floating_point_unavailable(file);
+      lf_indent(file, -2);
+    }
+  }
+}
+
+
+static void
+lf_print_c_cracker(lf *file,
+                  insn *instruction,
+                  insn_bits *expanded_bits,
+                  opcode_field *opcodes)
+{
+
+  /* function header */
+  lf_printf(file, "{\n");
+  lf_indent(file, +2);
+
+  lf_print_my_prefix(file,
+                    instruction->file_entry,
+                    1/*putting-value-in-cache*/);
+
+  lf_print_ptrace(file,
+                 1/*putting-value-in-cache*/);
+
+  lf_print_c_validate(file, instruction, opcodes);
+
+  lf_printf(file, "\n");
+  lf_printf(file, "{\n");
+  lf_indent(file, +2);
+  lf_print_c_extractions(file,
+                        instruction,
+                        expanded_bits,
+                        0/*get_value_from_cache*/,
+                        1/*put_value_in_cache*/);
+  lf_indent(file, -2);
+  lf_printf(file, "}\n");
+
+  /* return the function propper (main sorts this one out) */
+  lf_printf(file, "\n");
+  lf_printf(file, "/* semantic routine */\n");
+  table_entry_lf_c_line_nr(file, instruction->file_entry);
+  lf_printf(file, "return ");
+  lf_print_function_name(file,
+                        instruction->file_entry->fields[insn_name],
+                        expanded_bits,
+                        function_name_prefix_semantics);
+  lf_printf(file, ";\n");
+
+  lf_print_lf_c_line_nr(file);
+  lf_indent(file, -2);
+  lf_printf(file, "}\n");
+}
+
+
+static void
+lf_print_c_semantic(lf *file,
+                   insn *instruction,
+                   insn_bits *expanded_bits,
+                   opcode_field *opcodes)
+{
+
+  lf_printf(file, "{\n");
+  lf_indent(file, +2);
+
+  lf_print_my_prefix(file,
+                    instruction->file_entry,
+                    0/*not putting value in cache*/);
+  lf_putstr(file, semantic_local);
+  lf_printf(file, "\n");
+
+  lf_printf(file, "\n");
+  lf_print_c_extractions(file,
+                        instruction,
+                        expanded_bits,
+                        idecode_cache/*get_value_from_cache*/,
+                        0/*put_value_in_cache*/);
+
+  lf_print_ptrace(file,
+                 0/*put_value_in_cache*/);
+
+  /* validate the instruction, if a cache this has already been done */
+  if (!idecode_cache)
+    lf_print_c_validate(file, instruction, opcodes);
+
+  /* generate the profileing call - this is delayed until after the
+     instruction has been verified */
+  lf_printf(file, "\n");
+  lf_printf(file, "if (WITH_MON & MONITOR_INSTRUCTION_ISSUE)\n");
+  lf_printf(file, "  mon_issue(");
+  lf_print_function_name(file,
+                        instruction->file_entry->fields[insn_name],
+                        NULL,
+                        function_name_prefix_itable);
+  lf_printf(file, ", processor, cia);\n");
+
+  /* generate the code (or at least something */
+  if (instruction->file_entry->annex != NULL) {
+    /* true code */
+    lf_printf(file, "\n");
+    table_entry_lf_c_line_nr(file, instruction->file_entry);
+    lf_printf(file, "{\n");
+    lf_indent(file, +2);
+    lf_print_c_code(file, instruction->file_entry->annex);
+    lf_indent(file, -2);
+    lf_printf(file, "}\n");
+    lf_print_lf_c_line_nr(file);
+  }
+  else if (it_is("nop", instruction->file_entry->fields[insn_flags])) {
+    lf_print_lf_c_line_nr(file);
+  }
+  else if (it_is("f", instruction->file_entry->fields[insn_flags])) {
+    /* unimplemented floating point instruction - call for assistance */
+    lf_printf(file, "\n");
+    lf_printf(file, "/* unimplemented floating point instruction - call for assistance */\n");
+    table_entry_lf_c_line_nr(file, instruction->file_entry);
+    lf_putstr(file, "floating_point_assist_interrupt(processor, cia);\n");
+    lf_print_lf_c_line_nr(file);
+  }
+  else {
+    /* abort so it is implemented now */
+    table_entry_lf_c_line_nr(file, instruction->file_entry);
+    lf_putstr(file, "error(\"%s: unimplemented, cia=0x%x\\n\", my_prefix, cia);\n");
+    lf_print_lf_c_line_nr(file);
+    lf_printf(file, "\n");
+  }
+
+  /* the function footer */
+  lf_printf(file, "return nia;\n");
+  lf_indent(file, -2);
+  lf_printf(file, "}\n");
+}
+
+static void
+lf_print_c_semantic_function_header(lf *file,
+                                   char *basename,
+                                   insn_bits *expanded_bits)
+{
+  lf_printf(file, "\n");
+  lf_printf(file, "INLINE_SEMANTICS unsigned_word\n");
+  lf_print_function_name(file,
+                        basename,
+                        expanded_bits,
+                        function_name_prefix_semantics);
+  lf_printf(file, "\n(%s)\n",
+           (idecode_cache ? cache_semantic_formal : semantic_formal));
+}
+
+static void
+lf_print_c_semantic_function(lf *file,
+                            insn *instruction,
+                            insn_bits *expanded_bits,
+                            opcode_field *opcodes)
+{
+
+  /* build the semantic routine to execute the instruction */
+  lf_print_c_semantic_function_header(file,
+                                     instruction->file_entry->fields[insn_name],
+                                     expanded_bits);
+  lf_print_c_semantic(file,
+                     instruction,
+                     expanded_bits,
+                     opcodes);
+}
+
+
+static void
+semantics_c_leaf(insn_table *entry,
+                void *data,
+                int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(entry->nr_insn == 1
+        && entry->opcode == NULL
+        && entry->parent != NULL
+        && entry->parent->opcode != NULL);
+  lf_print_c_semantic_function(file,
+                              entry->insns,
+                              entry->expanded_bits,
+                              entry->parent->opcode);
+}
+
+static void
+semantics_c_insn(insn_table *table,
+                void *data,
+                insn *instruction)
+{
+  lf *file = (lf*)data;
+  lf_print_c_semantic_function(file, instruction,
+                              NULL, NULL);
+}
+
+static void
+semantics_c_function(insn_table *table,
+                    void *data,
+                    table_entry *function)
+{
+  lf *file = (lf*)data;
+  if (function->fields[function_type] == NULL
+      || function->fields[function_type][0] == '\0') {
+    lf_print_c_semantic_function_header(file,
+                                       function->fields[function_name],
+                                       NULL);
+  }
+  else {
+    lf_printf(file, "\n");
+    lf_printf(file, "INLINE_SEMANTICS %s\n%s(%s)\n",
+             function->fields[function_type],
+             function->fields[function_name],
+             function->fields[function_param]);
+  }
+  table_entry_lf_c_line_nr(file, function);
+  lf_printf(file, "{\n");
+  lf_indent(file, +2);
+  lf_print_c_code(file, function->annex);
+  lf_indent(file, -2);
+  lf_printf(file, "}\n");
+  lf_print_lf_c_line_nr(file);
+}
+
+
+
+static void 
+gen_semantics_c(insn_table *table, lf *file)
+{
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _SEMANTICS_C_\n");
+  lf_printf(file, "#define _SEMANTICS_C_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef STATIC_INLINE_SEMANTICS\n");
+  lf_printf(file, "#define STATIC_INLINE_SEMANTICS STATIC_INLINE\n");
+  lf_printf(file, "#endif\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#include \"cpu.h\"\n");
+  lf_printf(file, "#include \"idecode.h\"\n");
+  lf_printf(file, "#include \"semantics.h\"\n");
+  lf_printf(file, "\n");
+
+  /* output a definition (c-code) for all functions */
+  insn_table_traverse_function(table,
+                              file,
+                              semantics_c_function);
+
+  /* output a definition (c-code) for all instructions */
+  if (idecode_expand_semantics)
+    insn_table_traverse_tree(table,
+                            file,
+                            1,
+                            NULL, /* start */
+                            semantics_c_leaf,
+                            NULL, /* end */
+                            NULL); /* padding */
+  else
+    insn_table_traverse_insn(table,
+                            file,
+                            semantics_c_insn);
+
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif /* _SEMANTICS_C_ */\n");
+}
+
+
+/****************************************************************/
+
+static void
+gen_idecode_h(insn_table *table, lf *file)
+{
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _IDECODE_H_\n");
+  lf_printf(file, "#define _IDECODE_H_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef INLINE_IDECODE\n");
+  lf_printf(file, "#define INLINE_IDECODE\n");
+  lf_printf(file, "#endif\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#include \"idecode_expression.h\"\n");
+  lf_printf(file, "#include \"idecode_fields.h\"\n");
+  lf_printf(file, "#include \"idecode_branch.h\"\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#include \"icache.h\"\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "typedef unsigned_word idecode_semantic\n(%s);\n",
+           (idecode_cache ? cache_semantic_formal : semantic_formal));
+  lf_printf(file, "\n");
+  if (idecode_cache)
+    lf_printf(file, "INLINE_IDECODE idecode_semantic *idecode\n(%s);\n",
+             cache_idecode_formal);
+  else
+    lf_printf(file, "INLINE_IDECODE unsigned_word idecode_issue\n(%s);\n",
+             semantic_formal);
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif /* _IDECODE_H_ */\n");
+}
+
+
+/****************************************************************/
+
+
+static void
+idecode_table_start(insn_table *table,
+                   void *data,
+                   int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(depth == 0);
+  /* start of the table */
+  if (!table->opcode_rule->use_switch) {
+    lf_printf(file, "\n");
+    lf_printf(file, "static idecode_table_entry ");
+    lf_print_table_name(file, table);
+    lf_printf(file, "[] = {\n");
+  }
+}
+
+static void
+idecode_table_leaf(insn_table *entry,
+                  void *data,
+                  int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(entry->parent != NULL);
+  ASSERT(depth == 0);
+
+  /* add an entry to the table */
+  if (!entry->parent->opcode_rule->use_switch) {
+    if (entry->opcode == NULL) {
+      /* table leaf entry */
+      lf_printf(file, "  /*%d*/ { 0, 0, ", entry->opcode_nr);
+      lf_print_function_name(file,
+                            entry->insns->file_entry->fields[insn_name],
+                            entry->expanded_bits,
+                            (idecode_cache
+                             ? function_name_prefix_idecode
+                             : function_name_prefix_semantics));
+      lf_printf(file, " },\n");
+    }
+    else if (entry->opcode_rule->use_switch) {
+      /* table calling switch statement */
+      lf_printf(file, "  /*%d*/ { -1, 0, ",
+               entry->opcode_nr);
+      lf_print_table_name(file, entry);
+      lf_printf(file, " },\n");
+    }
+    else {
+      /* table `calling' another table */
+      lf_printf(file, "  /*%d*/ { ", entry->opcode_nr);
+      if (entry->opcode->is_boolean)
+       lf_printf(file, "MASK32(%d,%d), 0, ",
+                 entry->opcode->first, entry->opcode->last);
+      else
+       lf_printf(file, "%d, MASK32(%d,%d), ",
+                 insn_size - entry->opcode->last - 1,
+                 entry->opcode->first, entry->opcode->last);
+      lf_print_table_name(file, entry);
+      lf_printf(file, " },\n");
+    }
+  }
+}
+
+static void
+idecode_table_end(insn_table *table,
+                 void *data,
+                 int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(depth == 0);
+
+  if (!table->opcode_rule->use_switch) {
+    lf_printf(file, "};\n");
+  }
+}
+
+static void
+idecode_table_padding(insn_table *table,
+                     void *data,
+                     int depth,
+                     int opcode_nr)
+{
+  lf *file = (lf*)data;
+  ASSERT(depth == 0);
+
+  if (!table->opcode_rule->use_switch) {
+    lf_printf(file, "  /*%d*/ { 0, 0, %s_illegal },\n",
+             opcode_nr, (idecode_cache ? "idecode" : "semantic"));
+  }
+}
+
+
+/****************************************************************/
+
+
+void lf_print_idecode_switch
+(lf *file, 
+ insn_table *table);
+
+
+static void
+idecode_switch_start(insn_table *table,
+               void *data,
+               int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(depth == 0);
+  ASSERT(table->opcode_rule->use_switch);
+
+  lf_printf(file, "switch (EXTRACTED32(instruction, %d, %d)) {\n",
+           table->opcode->first, table->opcode->last);
+}
+
+
+static void
+idecode_switch_leaf(insn_table *entry,
+                   void *data,
+                   int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(entry->parent != NULL);
+  ASSERT(depth == 0);
+  ASSERT(entry->parent->opcode_rule->use_switch);
+
+  lf_printf(file, "case %d:\n", entry->opcode_nr);
+  lf_indent(file, +2);
+  {
+    if (entry->opcode == NULL) {
+      /* switch calling leaf */
+      lf_printf(file, "return ");
+      lf_print_function_name(file,
+                            entry->insns->file_entry->fields[insn_name],
+                            entry->expanded_bits,
+                            (idecode_cache
+                             ? function_name_prefix_idecode
+                             : function_name_prefix_semantics));
+      if (idecode_cache)
+       lf_printf(file, "(%s);\n", cache_idecode_actual);
+      else
+       lf_printf(file, "(%s);\n", semantic_actual);
+    }
+    else if (entry->opcode_rule->use_switch) {
+      /* switch calling switch */
+      lf_print_idecode_switch(file, entry);
+    }
+    else {
+      /* switch calling table */
+      lf_printf(file, "return ");
+      lf_print_idecode_table(file, entry);
+    }
+    lf_printf(file, "break;\n");
+  }
+  lf_indent(file, -2);
+}
+
+
+static void
+lf_print_idecode_switch_illegal(lf *file)
+{
+  lf_indent(file, +2);
+  lf_print_idecode_illegal(file);
+  lf_printf(file, "break;\n");
+  lf_indent(file, -2);
+}
+
+static void
+idecode_switch_end(insn_table *table,
+                  void *data,
+                  int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(depth == 0);
+  ASSERT(table->opcode_rule->use_switch);
+
+  if (table->opcode_rule->use_switch == 1) {
+    lf_printf(file, "default:\n");
+    lf_print_idecode_switch_illegal(file);
+  }
+  lf_printf(file, "}\n");
+}
+
+static void
+idecode_switch_padding(insn_table *table,
+                      void *data,
+                      int depth,
+                      int opcode_nr)
+{
+  lf *file = (lf*)data;
+
+  ASSERT(depth == 0);
+  ASSERT(table->opcode_rule->use_switch);
+
+  if (table->opcode_rule->use_switch > 1) {
+    lf_printf(file, "case %d:\n", opcode_nr);
+    lf_print_idecode_switch_illegal(file);
+  }
+}
+
+
+void
+lf_print_idecode_switch(lf *file, 
+                       insn_table *table)
+{
+  insn_table_traverse_tree(table,
+                          file,
+                          0,
+                          idecode_switch_start,
+                          idecode_switch_leaf,
+                          idecode_switch_end,
+                          idecode_switch_padding);
+}
+
+
+static void
+idecode_expand_if_switch(insn_table *table,
+                        void *data,
+                        int depth)
+{
+  lf *file = (lf*)data;
+
+  if (table->opcode_rule->use_switch
+      && table->parent != NULL /* don't expand the top one yet */
+      && !table->parent->opcode_rule->use_switch) {
+    lf_printf(file, "\n");
+    lf_printf(file, "STATIC_INLINE_IDECODE void\n");
+    lf_print_table_name(file, table);
+    lf_printf(file, "\n(%s)\n",
+             (idecode_cache ? cache_idecode_formal : semantic_formal));
+    lf_printf(file, "{\n");
+    {
+      lf_indent(file, +2);
+      lf_print_idecode_switch(file, table);
+      lf_indent(file, -2);
+    }
+    lf_printf(file, "}\n");
+  }
+}
+
+
+static void
+lf_print_c_cracker_function(lf *file,
+                           insn *instruction,
+                           insn_bits *expanded_bits,
+                           opcode_field *opcodes)
+{
+  /* if needed, generate code to enter this routine into a cache */
+  lf_printf(file, "\n");
+  lf_printf(file, "STATIC_INLINE_IDECODE idecode_semantic *\n");
+  lf_print_function_name(file,
+                        instruction->file_entry->fields[insn_name],
+                        expanded_bits,
+                        function_name_prefix_idecode);
+  lf_printf(file, "\n(%s)\n", cache_idecode_formal);
+
+  lf_print_c_cracker(file,
+                    instruction,
+                    expanded_bits,
+                    opcodes);
+}
+
+static void
+idecode_crack_leaf(insn_table *entry,
+                  void *data,
+                  int depth)
+{
+  lf *file = (lf*)data;
+  ASSERT(entry->nr_insn == 1
+        && entry->opcode == NULL
+        && entry->parent != NULL
+        && entry->parent->opcode != NULL);
+  lf_print_c_cracker_function(file,
+                             entry->insns,
+                             entry->expanded_bits,
+                             entry->opcode);
+}
+
+static void
+idecode_crack_insn(insn_table *entry,
+                  void *data,
+                  insn *instruction)
+{
+  lf *file = (lf*)data;
+  lf_print_c_cracker_function(file,
+                             instruction,
+                             NULL,
+                             NULL);
+}
+
+static void
+idecode_c_internal_function(insn_table *table,
+                           void *data,
+                           table_entry *function)
+{
+  lf *file = (lf*)data;
+  ASSERT(idecode_cache != 0);
+  if (it_is("internal", function->fields[insn_flags])) {
+    lf_printf(file, "\n");
+    lf_printf(file, "STATIC_INLINE_IDECODE idecode_semantic *\n");
+    lf_print_function_name(file,
+                          function->fields[insn_name],
+                          NULL,
+                          function_name_prefix_idecode);
+    lf_printf(file, "\n(%s)\n", cache_idecode_formal);
+    lf_printf(file, "{\n");
+    lf_indent(file, +2);
+    lf_printf(file, "/* semantic routine */\n");
+    table_entry_lf_c_line_nr(file, function);
+    lf_printf(file, "return ");
+    lf_print_function_name(file,
+                          function->fields[insn_name],
+                          NULL,
+                          function_name_prefix_semantics);
+    lf_printf(file, ";\n");
+
+    lf_print_lf_c_line_nr(file);
+    lf_indent(file, -2);
+    lf_printf(file, "}\n");
+  }
+}
+
+
+/****************************************************************/
+
+static void
+gen_idecode_c(insn_table *table, lf *file)
+{
+  int depth;
+
+  /* the intro */
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _IDECODE_C_\n");
+  lf_printf(file, "#define _IDECODE_C_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef STATIC_INLINE_IDECODE\n");
+  lf_printf(file, "#define STATIC_INLINE_IDECODE STATIC_INLINE\n");
+  lf_printf(file, "#endif\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#include \"cpu.h\"\n");
+  lf_printf(file, "#include \"idecode.h\"\n");
+  lf_printf(file, "#include \"semantics.h\"\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "typedef idecode_semantic *idecode_crack\n(%s);\n",
+           (idecode_cache ? cache_idecode_formal : semantic_formal));
+  lf_printf(file, "\n");
+  lf_printf(file, "typedef struct _idecode_table_entry {\n");
+  lf_printf(file, "  unsigned shift;\n");
+  lf_printf(file, "  unsigned mask;\n");
+  lf_printf(file, "  void *function_or_table;\n");
+  lf_printf(file, "} idecode_table_entry;\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "\n");
+
+  /* output `internal' invalid/floating-point unavailable functions
+     where needed */
+  if (idecode_cache) {
+    insn_table_traverse_function(table,
+                                file,
+                                idecode_c_internal_function);
+  }
+
+  /* output cracking functions where needed */
+  if (idecode_cache) {
+    if (idecode_expand_semantics)
+      insn_table_traverse_tree(table,
+                              file,
+                              1,
+                              NULL,
+                              idecode_crack_leaf,
+                              NULL,
+                              NULL);
+    else
+      insn_table_traverse_insn(table,
+                              file,
+                              idecode_crack_insn);
+  }
+
+
+  /* output tables where needed */
+  for (depth = insn_table_depth(table);
+       depth > 0;
+       depth--) {
+    insn_table_traverse_tree(table,
+                            file,
+                            1-depth,
+                            idecode_table_start,
+                            idecode_table_leaf,
+                            idecode_table_end,
+                            idecode_table_padding);
+  }
+
+  /* output switch functions where needed */
+  insn_table_traverse_tree(table,
+                          file,
+                          1,
+                          idecode_expand_if_switch, /* START */
+                          NULL, NULL, NULL);
+
+  /* output the main idecode routine */
+  lf_printf(file, "\n");
+  if (idecode_cache)
+    lf_printf(file, "INLINE_IDECODE idecode_semantic *\nidecode\n(%s)\n",
+             cache_idecode_formal);
+  else
+    lf_printf(file, "INLINE_IDECODE unsigned_word\nidecode_issue\n(%s)\n",
+             semantic_formal);
+  lf_printf(file, "{\n");
+  lf_indent(file, +2);
+  if (table->opcode_rule->use_switch)
+    lf_print_idecode_switch(file, table);
+  else
+    lf_print_idecode_table(file, table);
+  lf_indent(file, -2);
+  lf_printf(file, "}\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif\n");
+}
+
+
+/****************************************************************/
+
+static void
+itable_h_insn(insn_table *entry,
+             void *data,
+             insn *instruction)
+{
+  lf *file = (lf*)data;
+  lf_printf(file, "  ");
+  lf_print_function_name(file,
+                        instruction->file_entry->fields[insn_name],
+                        NULL,
+                        function_name_prefix_itable);
+  lf_printf(file, ",\n");
+}
+
+
+static void 
+gen_itable_h(insn_table *table, lf *file)
+{
+
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _ITABLE_H_\n");
+  lf_printf(file, "#define _ITABLE_H_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef INLINE_ITABLE\n");
+  lf_printf(file, "#define INLINE_ITABLE\n");
+  lf_printf(file, "#endif\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "\n");
+
+  /* output an enumerated type for each instruction */
+  lf_printf(file, "typedef enum {\n");
+  insn_table_traverse_insn(table,
+                          file,
+                          itable_h_insn);
+  lf_printf(file, "  nr_itable_entries,\n");
+  lf_printf(file, "} itable_index;\n");
+  lf_printf(file, "\n");
+
+  /* output the table that contains the actual instruction info */
+  lf_printf(file, "typedef struct _itable_instruction_info {\n");
+  lf_printf(file, "  itable_index nr;\n");
+  lf_printf(file, "  char *format;\n");
+  lf_printf(file, "  char *form;\n");
+  lf_printf(file, "  char *flags;\n");
+  lf_printf(file, "  char *nmemonic;\n");
+  lf_printf(file, "  char *name;\n");
+  lf_printf(file, "} itable_info;\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "extern itable_info itable[nr_itable_entries];\n");
+
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif /* _ITABLE_C_ */\n");
+
+}
+
+/****************************************************************/
+
+static void
+itable_c_insn(insn_table *entry,
+             void *data,
+             insn *instruction)
+{
+  lf *file = (lf*)data;
+  char **fields = instruction->file_entry->fields;
+  lf_printf(file, "  { ");
+  lf_print_function_name(file,
+                        instruction->file_entry->fields[insn_name],
+                        NULL,
+                        function_name_prefix_itable);
+  lf_printf(file, ",\n");
+  lf_printf(file, "    \"%s\",\n", fields[insn_format]);
+  lf_printf(file, "    \"%s\",\n", fields[insn_form]);
+  lf_printf(file, "    \"%s\",\n", fields[insn_flags]);
+  lf_printf(file, "    \"%s\",\n", fields[insn_nmemonic]);
+  lf_printf(file, "    \"%s\",\n", fields[insn_name]);
+  lf_printf(file, "    },\n");
+}
+
+
+static void 
+gen_itable_c(insn_table *table, lf *file)
+{
+
+  lf_print_copyleft(file);
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef _ITABLE_C_\n");
+  lf_printf(file, "#define _ITABLE_C_\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#ifndef STATIC_INLINE_ITABLE\n");
+  lf_printf(file, "#define STATIC_INLINE_ITABLE STATIC_INLINE\n");
+  lf_printf(file, "#endif\n");
+  lf_printf(file, "\n");
+  lf_printf(file, "#include \"itable.h\"\n");
+  lf_printf(file, "\n");
+
+  /* output the table that contains the actual instruction info */
+  lf_printf(file, "itable_info itable[nr_itable_entries] = {\n");
+  insn_table_traverse_insn(table,
+                          file,
+                          itable_c_insn);
+  lf_printf(file, "};\n");
+  lf_printf(file, "\n");
+
+  lf_printf(file, "\n");
+  lf_printf(file, "#endif /* _ITABLE_C_ */\n");
+
+}
+
+/****************************************************************/
+
+
+int
+main(int argc,
+     char **argv,
+     char **envp)
+{
+  insn_table *instructions = NULL;
+  icache_tree *cache_fields = NULL;
+  char *real_file_name = NULL;
+  int ch;
+
+  if (argc == 1) {
+    printf("Usage:\n");
+    printf("-f <filter-out-flag>  eg -f 64 to skip 64bit instructions\n");
+    printf("-[Ii] <instruction-table>  -I to dump internal table\n");
+    printf("-[Oo] <opcode-rules>\n");
+    printf("-[Kk] <cache-rules>\n");
+    printf("-[Ss] <schematic>  output schematic.h(S) schematic.c(s)\n");
+    printf("-[Dd] <schematic>  output idecode.h(S) idecode.c(s)\n");
+    printf("-[Tt] <table>      output itable.h(t) itable.c(t)\n");
+    printf("-[Cc] <schematic>  output icache.h(S) invalid(s)\n");
+    printf("-e  Expand (duplicate) semantic functions\n");
+    printf("-r <size>  Generate a cracking cache of <size>\n");
+    printf("-l  Supress includsion of CPP line numbering in output files\n");
+  }
+
+  while ((ch = getopt(argc, argv,
+                     "ler:f:I:i:O:o:K:k:n:S:s:D:d:T:t:C:")) != -1) {
+    fprintf(stderr, "\t-%c %s\n", ch, (optarg ? optarg : ""));
+    switch(ch) {
+    case 'l':
+      number_lines = 0;
+      break;
+    case 'e':
+      idecode_expand_semantics = 1;
+      break;
+    case 'r':
+      idecode_cache = a2i(optarg);
+      break;
+    case 'f':
+      {
+       filter *new_filter = ZALLOC(filter);
+       new_filter->flag = strdup(optarg);
+       new_filter->next = filters;
+       filters = new_filter;
+       break;
+      }
+    case 'I':
+    case 'i':
+      ASSERT(opcode_table != NULL);
+      ASSERT(cache_table != NULL);
+      instructions = insn_table_load_insns(optarg);
+      fprintf(stderr, "\texpanding ...\n");
+      insn_table_expand_insns(instructions);
+      fprintf(stderr, "\tcache fields ...\n");
+      cache_fields = insn_table_cache_fields(instructions);
+      if (ch == 'I') {
+       dump_traverse(instructions);
+       dump_insn_table(instructions, 0, 1);
+      }
+      break;
+    case 'O':
+    case 'o':
+      opcode_table = load_opcode_rules(optarg);
+      if (ch == 'O')
+       dump_opcode_rules(opcode_table, 0);
+      break;
+    case 'K':
+    case 'k':
+      cache_table = load_cache_rules(optarg);
+      if (ch == 'K')
+       dump_cache_rules(cache_table, 0);
+      break;
+    case 'n':
+      real_file_name = strdup(optarg);
+      break;
+    case 'S':
+    case 's':
+    case 'D':
+    case 'd':
+    case 'T':
+    case 't':
+    case 'C':
+      {
+       lf *file = lf_open(optarg, real_file_name, number_lines);
+       ASSERT(instructions != NULL);
+       switch (ch) {
+       case 'S':
+         gen_semantics_h(instructions, file);
+         break;
+       case 's':
+         gen_semantics_c(instructions, file);
+         break;
+       case 'D':
+         gen_idecode_h(instructions, file);
+         break;
+       case 'd':
+         gen_idecode_c(instructions, file);
+         break;
+       case 'T':
+         gen_itable_h(instructions, file);
+         break;
+       case 't':
+         gen_itable_c(instructions, file);
+         break;
+       case 'C':
+         gen_icache_h(cache_fields, file);
+         break;
+       }
+       lf_close(file);
+      }
+      real_file_name = NULL;
+      break;
+    default:
+      error("unknown option\n");
+    }
+  }
+  return 0;
+}
diff --git a/sim/ppc/misc.h b/sim/ppc/misc.h
new file mode 100644 (file)
index 0000000..0145f62
--- /dev/null
@@ -0,0 +1,48 @@
+/*  This file is part of the program psim.
+
+    Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+    */
+
+
+#include "filter_filename.h"
+
+extern void error
+(char *msg, ...);
+
+#define ASSERT(EXPRESSION) \
+do { \
+  if (!(EXPRESSION)) { \
+    error("%s:%d: assertion failed - %s\n", \
+         filter_filename (__FILE__), __LINE__, #EXPRESSION); \
+  } \
+} while (0)
+
+#define ZALLOC(TYPE) (TYPE*)zalloc(sizeof(TYPE))
+
+extern void *zalloc
+(long size);
+
+extern void dumpf
+(int indent, char *msg, ...);
+
+extern int it_is
+(const char *flag,
+ const char *flags);
+
+extern unsigned a2i
+(const char *a);
diff --git a/sim/ppc/ppc-instructions b/sim/ppc/ppc-instructions
new file mode 100644 (file)
index 0000000..2fa9c6b
--- /dev/null
@@ -0,0 +1,2414 @@
+#
+#   This file is part of the program psim.
+#
+#   Copyright (C) 1994-1995, Andrew Cagney <cagney@highland.com.au>
+#
+#   --
+#
+#   The pseudo-code that appears below, translated into C, was copied
+#   by Andrew Cagney of Moss Vale, Australia.
+#
+#   This pseudo-code is copied by permission from the publication
+#   "The PowerPC Architecture: A Specification for A New Family of
+#   RISC Processors" (ISBN 1-55860-316-6) copyright 1993, 1994 by
+#   International Business Machines Corporation.
+#
+#   THIS PERMISSION IS PROVIDED WITHOUT WARRANTY OF ANY KIND, EITHER
+#   EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES
+#   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+#   --
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#   --
+#
+#
+# Fields:
+#
+#      1       Instruction format as a `start-bit,content' pairs.
+#              the content is one of a digit, field name or `/' (aka.0)
+#
+#      2       Format specifier
+#
+#      3       Flags:  64 - 64bit only
+#                      f - floating point enabled required
+#
+#      4       short name
+#
+#      5       Description
+#
+
+# The following (illegal) instruction is `known' by gen and is
+# called when ever an illegal instruction is encountered
+::internal::illegal
+       program_interrupt(processor, cia,
+                         illegal_instruction_program_interrupt);
+       return 0;
+
+
+# The following (floating point unavailable) instruction is `known' by gen
+# and is called when ever an a floating point instruction is to be
+# executed but floating point is make unavailable by the MSR
+::internal::floating_point_unavailable
+       floating_point_unavailable_interrupt(processor, cia);
+       return 0;
+
+
+#
+# Floating point support functions
+#
+
+# Convert 32bit single to 64bit double
+unsigned64::function::DOUBLE:unsigned32 WORD
+       unsigned64 FRT;
+       if (EXTRACTED32(WORD, 1, 8) > 0
+           && EXTRACTED32(WORD, 1, 8) < 255) {
+         /* normalized operand */
+         int not_word_1_1 = !EXTRACTED32(WORD, 1, 1); /*2.6.3 bug*/
+         FRT = (INSERTED64(EXTRACTED32(WORD, 0, 1), 0, 1)
+                | INSERTED64(not_word_1_1, 2, 2)
+                | INSERTED64(not_word_1_1, 3, 3)
+                | INSERTED64(not_word_1_1, 4, 4)
+                | INSERTED64(EXTRACTED32(WORD, 2, 31), 5, (63 - 29)));
+       }
+       else if (EXTRACTED32(WORD, 1, 8) == 0
+                && EXTRACTED32(WORD, 9, 31) != 0) {
+         /* denormalized operand */
+         int sign = EXTRACTED32(WORD, 0, 0);
+         int exp = -126;
+         unsigned64 frac = INSERTED64(EXTRACTED32(WORD, 9, 31), 1, (52 - 29));
+         /* normalize the operand */
+         while (MASKED64(frac, 0, 0) == 0) {
+           frac <<= 1;
+           exp -= 1;
+         }
+         FRT = (INSERTED64(sign, 0, 0)
+                | INSERTED64(exp + 1023, 1, 11)
+                | INSERTED64(EXTRACTED64(frac, 1, 52), 12, 63));
+       }
+       else if (EXTRACTED32(WORD, 1, 8) == 255
+                || EXTRACTED32(WORD, 1, 31) == 0) {
+         FRT = (INSERTED64(EXTRACTED32(WORD, 0, 1), 0, 1)
+                | INSERTED64(EXTRACTED32(WORD, 1, 1), 2, 2)
+                | INSERTED64(EXTRACTED32(WORD, 1, 1), 3, 3)
+                | INSERTED64(EXTRACTED32(WORD, 1, 1), 4, 4)
+                | INSERTED64(EXTRACTED32(WORD, 2, 31), 5, (63 - 29)));
+       }
+       else {
+         error("DOUBLE - unknown case\n");
+         FRT = 0;
+       }
+       return FRT;
+
+# Convert 64bit single to 32bit double
+unsigned32::function::SINGLE:unsigned64 FRS
+       unsigned32 WORD;
+       if (EXTRACTED64(FRS, 1, 11) > 896
+           || EXTRACTED64(FRS, 1, 63) == 0) {
+         /* no denormalization required (includes Zero/Infinity/NaN) */
+         WORD = (INSERTED32(EXTRACTED64(FRS, 0, 1), 0, 1)
+                 | INSERTED32(EXTRACTED64(FRS, 5, 34), 2, 31));
+       }
+       else if (874 <= EXTRACTED64(FRS, 1, 11)
+                && EXTRACTED64(FRS, 1, 11) <= 896) {
+         /* denormalization required */
+         int sign = EXTRACTED64(FRS, 0, 0);
+         int exp = EXTRACTED64(FRS, 1, 11) - 1023;
+         unsigned64 frac = (BIT64(0)
+                            | INSERTED64(EXTRACTED64(FRS, 12, 63), 1, 52));
+         /* denormalize the operand */
+         while (exp < -126) {
+           frac = INSERTED64(EXTRACTED64(frac, 0, 62), 1, 63);
+           exp += 1;
+         }
+         WORD = (INSERTED32(sign, 0, 0)
+                 | INSERTED32(0x00, 1, 8)
+                 | INSERTED32(EXTRACTED64(frac, 1, 23), 9, 31));
+       }
+       else {
+         WORD = 0x0; /* ??? */
+       }         
+       return WORD;
+
+
+# round 64bit double to 64bit but single
+void::function::Round_Single:cpu *processor, int sign, int *exp, unsigned64 *frac_grx
+       /* comparisons ignore u bits */
+       unsigned64 out;
+       int inc = 0;
+       int lsb = EXTRACTED64(*frac_grx, 23, 23);
+       int gbit = EXTRACTED64(*frac_grx, 24, 24);
+       int rbit = EXTRACTED64(*frac_grx, 25, 25);
+       int xbit = EXTRACTED64(*frac_grx, 26, 55) != 0;
+       if ((FPSCR & fpscr_rn) == fpscr_rn_round_to_nearest) {
+         if (lsb == 1 && gbit == 1) inc = 1;
+         if (lsb == 0 && gbit == 1 && rbit == 1) inc = 1;
+         if (lsb == 0 && gbit == 1 && xbit == 1) inc = 1;
+       }
+       if ((FPSCR & fpscr_rn) == fpscr_rn_round_towards_pos_infinity) {
+         if (sign == 0 && gbit == 1) inc = 1;
+         if (sign == 0 && rbit == 1) inc = 1;
+         if (sign == 0 && xbit == 1) inc = 1;
+       }
+       if ((FPSCR & fpscr_rn) == fpscr_rn_round_towards_neg_infinity) {
+         if (sign == 1 && gbit == 1) inc = 1;
+         if (sign == 1 && rbit == 1) inc = 1;
+         if (sign == 1 && xbit == 1) inc = 1;
+       }
+       /* work out addition in low 25 bits of out */
+       out = EXTRACTED64(*frac_grx, 0, 23) + inc;
+       *frac_grx = INSERTED64(out, 0, 23);
+       if (out & BIT64(64 - 23 - 1 - 1)) {
+         *frac_grx = (BIT64(0) |
+                      INSERTED64(EXTRACTED64(*frac_grx, 0, 22), 1, 23));
+         *exp = *exp + 1;
+       }
+       /* frac_grx[24:52] = 0 already */
+       FPSCR_SET_FR(inc);
+       FPSCR_SET_FI(gbit || rbit || xbit);
+
+
+#
+void::function::Round_Integer:cpu *processor, int sign, unsigned64 *frac, int *frac64, int gbit, int rbit, int xbit, fpscreg round_mode
+       int inc = 0;
+       if (round_mode == fpscr_rn_round_to_nearest) {
+         if (*frac64 == 1 && gbit == 1) inc = 1;
+         if (*frac64 == 0 && gbit == 1 && rbit == 1) inc = 1;
+         if (*frac64 == 0 && gbit == 1 && xbit == 1) inc = 1;
+       }
+       if (round_mode == fpscr_rn_round_towards_pos_infinity) {
+         if (sign == 0 && gbit == 1) inc = 1;
+         if (sign == 0 && rbit == 1) inc = 1;
+         if (sign == 0 && xbit == 1) inc = 1;
+       }
+       if (round_mode == fpscr_rn_round_towards_neg_infinity) {
+         if (sign == 1 && gbit == 1) inc = 1;
+         if (sign == 1 && rbit == 1) inc = 1;
+         if (sign == 1 && xbit == 1) inc = 1;
+       }
+       /* frac[0:64] = frac[0:64} + inc */
+       *frac += (*frac64 && inc ? 1 : 0);
+       *frac64 = (*frac64 + inc) & 0x1;
+       FPSCR_SET_FR(inc);
+       FPSCR_SET_FI(gbit | rbit | xbit);
+       
+
+void::function::Round_Float:cpu *processor, int sign, int *exp, unsigned64 *frac, fpscreg round_mode
+       int carry_out;
+       int inc = 0;
+       int lsb = EXTRACTED64(*frac, 52, 52);
+       int gbit = EXTRACTED64(*frac, 53, 53);
+       int rbit = EXTRACTED64(*frac, 54, 54);
+       int xbit = EXTRACTED64(*frac, 55, 55);
+       if (round_mode == fpscr_rn_round_to_nearest) {
+         if (lsb == 1 && gbit == 1) inc = 1;
+         if (lsb == 0 && gbit == 1 && rbit == 1) inc = 1;
+         if (lsb == 0 && gbit == 1 && xbit == 1) inc = 1;
+       }
+       if (round_mode == fpscr_rn_round_towards_pos_infinity) {
+         if (sign == 0 && gbit == 1) inc = 1;
+         if (sign == 0 && rbit == 1) inc = 1;
+         if (sign == 0 && xbit == 1) inc = 1;
+       }
+       if (round_mode == fpscr_rn_round_towards_neg_infinity) {
+         if (sign == 1 && gbit == 1) inc = 1;
+         if (sign == 1 && rbit == 1) inc = 1;
+         if (sign == 1 && xbit == 1) inc = 1;
+       }
+       /* frac//carry_out = frac + inc */
+       *frac = (*frac >> 1) + (INSERTED64(inc, 52, 52) >> 1);
+       carry_out = EXTRACTED64(*frac, 0, 0);
+       *frac <<= 1;
+       if (carry_out == 1) *exp = *exp + 1;
+       FPSCR_SET_FR(inc);
+       FPSCR_SET_FI(gbit | rbit | xbit);
+       FPSCR_SET_XX(FPSCR & fpscr_fi);
+
+
+# conversion of FP to integer
+void::function::convert_to_integer:cpu *processor, unsigned_word cia, unsigned64 *frt, unsigned64 frb, fpscreg round_mode, int tgt_precision
+       int i;
+       int exp = 0;
+       unsigned64 frac = 0;
+       int frac64 = 0;
+       int gbit = 0;
+       int rbit = 0;
+       int xbit = 0;
+       int sign = EXTRACTED64(frb, 0, 0);
+       if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 63) == 0)
+         goto Infinity_Operand;
+       if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 12) == 0)
+         goto SNaN_Operand;
+       if (EXTRACTED64(frb, 1, 11) == 2047 && EXTRACTED64(frb, 12, 12) == 1)
+         goto QNaN_Operand;
+       if (EXTRACTED64(frb, 1, 11) > 1086) goto Large_Operand;
+       if (EXTRACTED64(frb, 1, 11) > 0) exp = EXTRACTED64(frb, 1, 11) - 1023;
+       if (EXTRACTED64(frb, 1, 11) == 0) exp = -1022;
+       if (EXTRACTED64(frb, 1, 11) > 0) { /* normal */
+         frac = BIT64(1) | INSERTED64(EXTRACTED64(frb, 12, 63), 2, 53);
+         frac64 = 0;
+       }
+       if (EXTRACTED64(frb, 1, 11) == 0) { /* denorm */
+         frac = INSERTED64(EXTRACTED64(frb, 12, 63), 2, 53);
+         frac64 = 0;
+       }
+       gbit = 0, rbit = 0, xbit = 0;
+       for (i = 1; i <= 63 - exp; i++) {
+         xbit = rbit | xbit;
+         rbit = gbit;
+         gbit = frac64;
+         frac64 = EXTRACTED64(frac, 63, 63);
+         frac = INSERTED64(EXTRACTED64(frac, 0, 62), 1, 63);
+       }
+       Round_Integer(processor, sign, &frac, &frac64, gbit, rbit, xbit, round_mode);
+       if (sign == 1) { /* frac[0:64] = ~frac[0:64] + 1 */
+         frac = ~frac;
+         frac64 ^= 1;
+         frac += (frac64 ? 1 : 0);
+         frac64 = (frac64 + 1) & 0x1;
+       }
+       if (tgt_precision == 32 /* can ignore frac64 in compare */
+           && (signed64)frac > (signed64)MASK64(33+1, 63)/*2^31-1 >>1*/)
+         goto Large_Operand;
+       if (tgt_precision == 64 /* can ignore frac64 in compare */
+           && (signed64)frac > (signed64)MASK64(1+1, 63)/*2^63-1 >>1*/)
+         goto Large_Operand;
+       if (tgt_precision == 32 /* can ignore frac64 in compare */
+           && (signed64)frac < (signed64)MASK64(0, 32+1)/*-2^31 >>1*/)
+         goto Large_Operand;
+       if (tgt_precision == 64 /* can ignore frac64 in compare */
+           && (signed64)frac < (signed64)MASK64(0, 0+1)/*-2^63 >>1*/)
+         goto Large_Operand;
+       FPSCR_SET_XX(FPSCR & fpscr_fi);
+       if (tgt_precision == 32)
+         *frt = MASKED64(*frt, 0, 31) | (EXTRACTED64(frac, 33, 63) << 1) | frac64;
+       if (tgt_precision == 64)
+         *frt = (EXTRACTED64(frac, 1, 63) << 1) | frac64;
+       /*FPSCR[fprf] = undefined */
+       goto Done;
+       /**/
+       Infinity_Operand:
+         FPSCR_SET_FR(0);
+         FPSCR_SET_FI(0);
+         FPSCR_OR_VX(fpscr_vxcvi);
+         if ((FPSCR & fpscr_ve) == 0) {
+           if (tgt_precision == 32) {
+             if (sign == 0) *frt = MASKED64(*frt, 0, 31) | 0x7FFFFFFF;
+             if (sign == 1) *frt = MASKED64(*frt, 0, 31) | 0x80000000;
+           }
+           else {
+             if (sign == 0) *frt = MASK64(1, 63); /*0x7FFF_FFFF_FFFF_FFFF*/
+             if (sign == 1) *frt = BIT64(0); /*0x8000_0000_0000_0000*/
+           }
+           /* FPSCR[FPRF] = undefined */
+         }
+         goto Done;
+       /**/
+       SNaN_Operand:
+         FPSCR_SET_FR(0);
+         FPSCR_SET_FI(0);
+         FPSCR_OR_VX(fpscr_vxsnan | fpscr_vxcvi);
+         if ((FPSCR & fpscr_ve) == 0) {
+           if (tgt_precision == 32) *frt = MASKED64(*frt, 0, 31) | 0x80000000;
+           if (tgt_precision == 64) *frt = BIT64(0); /*0x8000_0000_0000_0000*/
+           /* FPSCR[fprf] = undefined */
+         }
+         goto Done;
+       /**/
+       QNaN_Operand:
+         FPSCR_SET_FR(0);
+         FPSCR_SET_FI(0);
+         FPSCR_OR_VX(fpscr_vxcvi);
+         if ((FPSCR & fpscr_ve) == 0) {
+           if (tgt_precision == 32) *frt = MASKED64(*frt, 0, 31) | 0x80000000;
+           if (tgt_precision == 64) *frt = BIT64(0);/*0x8000_0000_0000_0000*/
+           /* FPSCR[fprf] = undefined */
+         }
+         goto Done;
+       /**/
+       Large_Operand:
+         FPSCR_SET_FR(0);
+         FPSCR_SET_FI(0);
+         FPSCR_OR_VX(fpscr_vxcvi);
+         if ((FPSCR & fpscr_ve) == 0) {
+           if (tgt_precision == 32) {
+             if (sign == 0) *frt = MASKED64(*frt, 0, 31) | 0x7fffffff;
+             if (sign == 1) *frt = MASKED64(*frt, 0, 31) | 0x80000000;
+           }
+           else {
+             if (sign == 0) *frt = MASK64(1, 63); /*0x7FFF_FFFF_FFFF_FFFF*/
+             if (sign == 1) *frt = BIT64(0); /*0x8000_0000_0000_0000*/
+           }
+           /* FPSCR[fprf] = undefined */
+         }
+       /**/
+       Done:
+
+
+# extract out raw fields of a FP number
+int::function::sign:unsigned64 FRS
+       return (MASKED64(FRS, 0, 0)
+               ? -1
+               : 1);
+int::function::biased_exp:unsigned64 frs, int single
+       if (single)
+         return EXTRACTED64(frs, 1, 8);
+       else
+         return EXTRACTED64(frs, 1, 11);
+unsigned64::function::fraction:unsigned64 frs, int single
+       if (single)
+         return EXTRACTED64(frs, 9, 31);
+       else
+         return EXTRACTED64(frs, 12, 63);
+
+# a number?, each of the below return +1 or -1 (based on sign bit)
+# if true.
+int::function::is_nor:unsigned64 frs, int single
+       int exp = biased_exp(frs, single);
+       return (exp >= 1
+               && exp <= (single ? 254 : 2046));
+int::function::is_zero:unsigned64 FRS
+       return (MASKED64(FRS, 1, 63) == 0
+               ? sign(FRS)
+               : 0);
+int::function::is_den:unsigned64 frs, int single
+       int exp = biased_exp(frs, single);
+       unsigned64 frac = fraction(frs, single);
+       return (exp == 0 && frac != 0
+               ? sign(frs)
+               : 0);
+int::function::is_inf:unsigned64 frs, int single
+       int exp = biased_exp(frs, single);
+       int frac = fraction(frs, single);
+       return (exp == (single ? 255 : 2047) && frac == 0
+               ? sign(frs)
+               : 0);
+int::function::is_NaN:unsigned64 frs, int single
+       int exp = biased_exp(frs, single);
+       int frac = fraction(frs, single);
+       return (exp == (single ? 255 : 2047) && frac != 0
+               ? sign(frs)
+               : 0);
+int::function::is_SNaN:unsigned64 frs, int single
+       return (is_NaN(frs, single)
+               && !(frs & (single ? MASK64(9, 9) : MASK64(12, 12)))
+                    ? sign(frs)
+                    : 0);
+int::function::is_QNaN:unsigned64 frs, int single
+       return (is_NaN(frs, single) && !is_SNaN(frs, single));
+int::function::is_less_than:unsigned64 *fra, unsigned64 *frb
+       return *(double*)fra < *(double*)frb;
+int::function::is_greater_than:unsigned64 *fra, unsigned64 *frb
+       return *(double*)fra > *(double*)frb;
+int::function::is_equan_to:unsigned64 *fra, unsigned64 *frb
+       return *(double*)fra == *(double*)frb;
+       
+
+# which quiet nan should become the result
+unsigned64::function::select_qnan:unsigned64 fra, unsigned64 frb, unsigned64 frc, int instruction_is_frsp, int generate_qnan, int single
+       unsigned64 frt = 0;
+       if (is_NaN(fra, single))
+         frt = fra;
+       else if (is_NaN(frb, single))
+         if (instruction_is_frsp)
+           frt = MASKED64(frb, 0, 34);
+         else
+           frt = frb;
+       else if (is_NaN(frc, single))
+         frt = frc;
+       else if (generate_qnan)
+         frt = MASK64(1, 12); /* 0x7FF8_0000_0000_0000 */
+       else
+         error("select_qnan - default reached\n");
+       return frt;
+       
+
+# detect invalid operation
+int::function::is_invalid_operation:cpu *processor, unsigned_word cia, unsigned64 fra, unsigned64 frb, fpscreg check, int single, int negate
+       int fail = 0;
+       if ((check & fpscr_vxsnan)
+           && (is_SNaN(fra, single) || is_SNaN(frb, single))) {
+         FPSCR_OR_VX(fpscr_vxsnan);
+         fail = 1;
+       }
+       if ((check & fpscr_vxisi)
+           && (is_inf(fra, single) && is_inf(frb, single))
+           && ((negate && sign(fra) != sign(frb))
+               || (!negate && sign(fra) == sign(frb)))) {
+          /*FIXME: don't handle inf-inf VS inf+-inf */
+         FPSCR_OR_VX(fpscr_vxisi);
+         fail = 1;
+       }
+       if ((check & fpscr_vxidi)
+           && (is_inf(fra, single) && is_inf(frb, single))) {
+         FPSCR_OR_VX(fpscr_vxidi);
+         fail = 1;
+       }
+       if ((check & fpscr_vxzdz)
+           && (is_zero(fra) && is_zero(frb))) {
+         FPSCR_OR_VX(fpscr_vxzdz);
+         fail = 1;
+       }
+       if ((check & fpscr_vximz)
+           && (is_zero(fra) && is_inf(frb, single))) {
+         FPSCR_OR_VX(fpscr_vximz);
+         fail = 1;
+       }
+       if ((check & fpscr_vxvc)
+           && (is_NaN(fra, single) || is_NaN(frb, single))) {
+         FPSCR_OR_VX(fpscr_vxvc);
+         fail = 1;
+       }
+       if ((check & fpscr_vxsoft)) {
+         FPSCR_OR_VX(fpscr_vxsoft);
+         fail = 1;
+       }
+       if ((check & fpscr_vxsqrt)
+           && sign(fra) < 0) {
+         FPSCR_OR_VX(fpscr_vxsqrt);
+         fail = 1;
+       }
+       /* if ((check && fpscr_vxcvi) {
+           && (is_inf(fra, single) || is_NaN(fra, single) || is_large(fra, single)))
+         FPSCR_OR_VX(fpscr_vxcvi);
+         fail = 1;
+       }
+       */
+       return fail;
+
+
+       
+
+
+# handle case of invalid operation
+void::function::invalid_arithemetic_operation:cpu *processor, unsigned_word cia, unsigned64 *frt, unsigned64 fra, unsigned64 frb, unsigned64 frc, int instruction_is_frsp, int instruction_is_convert_to_64bit, int instruction_is_convert_to_32bit, int single
+       if (FPSCR & fpscr_ve) {
+         /* invalid operation exception enabled */
+         /* FRT unchaged */
+         FPSCR_SET_FR(0);
+         FPSCR_SET_FI(0);
+         /* fpscr_FPRF unchanged */
+       }
+       else {
+         /* invalid operation exception disabled */
+         if (instruction_is_convert_to_64bit) {
+           error("oopsi");
+         }
+         else if (instruction_is_convert_to_32bit) {
+           error("oopsi");
+         }
+         else { /* arrith, frsp */
+           *frt = select_qnan(fra, frb, frc,
+                              instruction_is_frsp, 0/*generate*/, single);
+           FPSCR_SET_FR(0);
+           FPSCR_SET_FI(0);
+           FPSCR_SET_FPRF(fpscr_rf_quiet_nan);
+         }
+       }
+
+
+
+
+#
+# I.2.4.1 Branch Instructions
+#
+0.18,6.LI,30.AA,31.LK:I:t::Branch
+       if (AA) NIA = IEA(EXTS(LI_0b00));
+       else    NIA = IEA(CIA + EXTS(LI_0b00));
+       if (LK) LR = (spreg)CIA+4;
+0.16,6.BO,11.BI,16.BD,30.AA,31.LK:B:t::Branch Conditional
+       int M, ctr_ok, cond_ok;
+       if (is_64bit_implementation && is_64bit_mode) M = 0;
+       else                                          M = 32;
+       if (!BO{2}) CTR = CTR - 1;
+       ctr_ok = BO{2} || ((MASKED(CTR, M, 63) != 0) != (BO{3}));
+       cond_ok = BO{0} || ((CR{BI}) == (BO{1}));
+       if (ctr_ok && cond_ok)
+         if (AA) NIA = IEA(EXTS(BD_0b00));
+         else    NIA = IEA(CIA + EXTS(BD_0b00));
+       if (LK) LR = (spreg)IEA(CIA + 4);
+0.19,6.BO,11.BI,16./,21.16,31.LK:XL:t::Branch Conditional to Link Register
+       int M, ctr_ok, cond_ok;
+       if (is_64bit_implementation && is_64bit_mode) M = 0;
+       else                                          M = 32;
+       if (!BO{2}) CTR = CTR - 1;
+       ctr_ok = BO{2} || ((MASKED(CTR, M, 63) != 0) != BO{3});
+       cond_ok = BO{0} || (CR{BI} == BO{1});
+       if (ctr_ok && cond_ok) NIA = IEA(LR_0b00);
+       if (LK) LR = (spreg)IEA(CIA + 4);
+0.19,6.BO,11.BI,16./,21.528,31.LK:XL:t::Branch Conditional to Count Register
+       int cond_ok;
+       cond_ok = BO{0} || (CR{BI} == BO{1});
+       if (cond_ok) NIA = IEA(CTR_0b00);
+       if (LK) LR = (spreg)IEA(CIA + 4);
+
+#
+# I.2.4.2 System Call Instruction
+#
+0.17,6./,11./,16./,30.1,31./:SC:t::System Call
+       system_call_interrupt(processor, cia);
+
+#
+# I.2.4.3 Condition Register Logical Instructions
+#
+0.19,6.BT,11.BA,16.BB,21.257,31./:XL::crand:Condition Register AND
+       BLIT32(CR, BT, CR{BA} && CR{BB});
+0.19,6.BT,11.BA,16.BB,21.449,31./:XL::cror:Condition Register OR
+       BLIT32(CR, BT, CR{BA} || CR{BB});
+0.19,6.BT,11.BA,16.BB,21.193,31./:XL::crxor:Condition Register XOR
+       BLIT32(CR, BT, CR{BA} != CR{BB});
+0.19,6.BT,11.BA,16.BB,21.225,31./:XL::crnand:Condition Register NAND
+       BLIT32(CR, BT, !(CR{BA} && CR{BB}));
+0.19,6.BT,11.BA,16.BB,21.33,31./:XL::crnor:Condition Register NOR
+       BLIT32(CR, BT, !(CR{BA} || CR{BB}));
+0.19,6.BT,11.BA,16.BB,21.289,31./:XL::creqv:Condition Register Equivalent
+       BLIT32(CR, BT, CR{BA} == CR{BB});
+0.19,6.BT,11.BA,16.BB,21.129,31./:XL::crandc:Condition Register AND with Complement
+       BLIT32(CR, BT, CR{BA} && !CR{BB});
+0.19,6.BT,11.BA,16.BB,21.417,31./:XL::crorc:Condition Register OR with Complement
+       BLIT32(CR, BT, CR{BA} || !CR{BB});
+
+#
+# I.2.4.4 Condition Register Field Instruction
+#
+0.19,6.BF,9./,11.BFA,14./,16./,21.0,31./:XL:::Move Condition Register Field
+       MBLIT32(CR, 4*BF, 4*BF+3, EXTRACTED32(CR, 4*BFA, 4*BFA+3));
+
+
+#
+# I.3.3.2 Fixed-Point Load Instructions
+#
+
+0.34,6.RT,11.RA,16.D:D:::Load Byte and Zero
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + EXTS(D);
+       *rT = MEM(unsigned, EA, 1);
+0.31,6.RT,11.RA,16.RB,21.87,31./:X:::Load Byte and Zero Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       *rT = MEM(unsigned, EA, 1);
+0.35,6.RT,11.RA,16.D:D:::Load Byte and Zero with Update
+       unsigned_word EA;
+       if (RA == 0 || RA == RT)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + EXTS(D);
+       *rT = MEM(unsigned, EA, 1);
+       *rA = EA;
+0.31,6.RT,11.RA,16.RB,21.119,31./:X:::Load Byte and Zero with Update Indexed
+       unsigned_word EA;
+       if (RA == 0 || RA == RT)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + *rB;
+       *rT = MEM(unsigned, EA, 1);
+       *rA = EA;
+
+0.40,6.RT,11.RA,16.D:D:::Load Halfword and Zero
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + EXTS(D);
+       *rT = MEM(unsigned, EA, 2);
+0.31,6.RT,11.RA,16.RB,21.279,31./:X:::Load Halfword and Zero Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       *rT = MEM(unsigned, EA, 2);
+0.41,6.RT,11.RA,16.D:D:::Load Halfword and Zero with Update
+       unsigned_word EA;
+       if (RA == 0 || RA == RT)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + EXTS(D);
+       *rT = MEM(unsigned, EA, 2);
+       *rA = EA;
+0.31,6.RT,11.RA,16.RB,21.311,31./:X:::Load Halfword and Zero with Update Indexed
+       unsigned_word EA;
+       if (RA == 0 || RA == RT)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + *rB;
+       *rT = MEM(unsigned, EA, 2);
+       *rA = EA;
+
+0.42,6.RT,11.RA,16.D:D:::Load Halfword Algebraic
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + EXTS(D);
+       *rT = MEM(signed, EA, 2);
+0.31,6.RT,11.RA,16.RB,21.343,31./:X:::Load Halfword Algebraic Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       *rT = MEM(signed, EA, 2);
+0.43,6.RT,11.RA,16.D:D:::Load Halfword Algebraic with Update
+       unsigned_word EA;
+       if (RA == 0 || RA == RT)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + EXTS(D);
+       *rT = MEM(signed, EA, 2);
+0.31,6.RT,11.RA,16.RB,21.375,31./:X:::Load Halfword Algebraic with Update Indexed
+       unsigned_word EA;
+       if (RA == 0 || RA == RT)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + *rB;
+       *rT = MEM(signed, EA, 2);
+       *rA = EA;
+
+0.32,6.RT,11.RA,16.D:D:::Load Word and Zero
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + EXTS(D);
+       *rT = MEM(unsigned, EA, 4);
+0.31,6.RT,11.RA,16.RB,21.23,31./:X:::Load Word and Zero Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       *rT = MEM(unsigned, EA, 4);
+0.33,6.RT,11.RA,16.D:D:::Load Word and Zero with Update
+       unsigned_word EA;
+       if (RA == 0 || RA == RT)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + EXTS(D);
+       *rT = MEM(unsigned, EA, 4);
+       *rA = EA;
+0.31,6.RT,11.RA,16.RB,21.55,31./:X:::Load Word and Zero with Update Indexed
+       unsigned_word EA;
+       if (RA == 0 || RA == RT)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + *rB;
+       *rT = MEM(unsigned, EA, 4);
+       *rA = EA;
+
+0.58,6.RT,11.RA,16.DS,30.2:DS:64::Load Word Algebraic
+#      unsigned_word b;
+#      unsigned_word EA;
+#      if (RA == 0) b = 0;
+#      else         b = *rA;
+#      EA = b + EXTS(DS_0b00);
+#      *rT = MEM(signed, EA, 4);
+0.31,6.RT,11.RA,16.RB,21.341,31./:X:64::Load Word Algebraic Indexed
+#      unsigned_word b;
+#      unsigned_word EA;
+#      if (RA == 0) b = 0;
+#      else         b = *rA;
+#      EA = b + *rB;;
+#      *rT = MEM(signed, EA, 4);
+0.31,6.RT,11.RA,16.RB,21.373,31./:X:64::Load Word Algebraic with Update Indexed
+#      unsigned_word EA;
+#      if (RA == 0 || RA == RT)
+#        program_interrupt(processor, cia
+#                          illegal_instruction_program_interrupt);
+#      EA = *rA + *rB;
+#      *rT = MEM(signed, EA, 4);
+#      *rA = EA;
+
+0.58,6.RT,11.RA,16.DS,30.0:DS:64::Load Doubleword
+#      unsigned_word b;
+#      unsigned_word EA;
+#      if (RA == 0) b = 0;
+#      else         b = *rA;
+#      EA = b + EXTS(DS_0b00);
+#      *rT = MEM(unsigned, EA, 8);
+0.31,6.RT,11.RA,16.RB,21.21,31./:X:64::Load Doubleword Indexed
+#      unsigned_word b;
+#      unsigned_word EA;
+#      if (RA == 0) b = 0;
+#      else         b = *rA;
+#      EA = b + *rB;
+#      *rT = MEM(unsigned, EA, 8);
+0.58,6.RT,11.RA,16.DS,30.1:DS:64::Load Doubleword with Update
+#      unsigned_word EA;
+#      if (RA == 0 || RA == RT)
+#        program_interrupt(processor, cia
+#                          illegal_instruction_program_interrupt);
+#      EA = *rA + EXTS(DS_0b00);
+#      *rT = MEM(unsigned, EA, 8);
+#      *rA = EA;
+0.31,6.RT,11.RA,16.RB,21.53,31./:DS:64::Load Doubleword with Update Indexed
+#      unsigned_word EA;
+#      if (RA == 0 || RA == RT)
+#        program_interrupt(processor, cia
+#                          illegal_instruction_program_interrupt);
+#      EA = *rA + *rB;
+#      *rT = MEM(unsigned, EA, 8);
+#      *rA = EA;
+
+
+
+#
+# I.3.3.3 Fixed-Point Store Instructions
+#
+
+0.38,6.RS,11.RA,16.D:D:::Store Byte
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + EXTS(D);
+       STORE(EA, 1, *rS);
+0.31,6.RS,11.RA,16.RB,21.215,31./:X:::Store Byte Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       STORE(EA, 1, *rS);
+0.39,6.RS,11.RA,16.D:D:::Store Byte with Update
+       unsigned_word EA;
+       if (RA == 0)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + EXTS(D);
+       STORE(EA, 1, *rS);
+       *rA = EA;
+0.31,6.RS,11.RA,16.RB,21.247,31./:X:::Store Byte with Update Indexed
+       unsigned_word EA;
+       if (RA == 0)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + *rB;
+       STORE(EA, 1, *rS);
+       *rA = EA;
+
+0.44,6.RS,11.RA,16.D:D:::Store Half Word
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + EXTS(D);
+       STORE(EA, 2, *rS);
+0.31,6.RS,11.RA,16.RB,21.407,31./:X:::Store Half Word Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       STORE(EA, 2, *rS);
+0.45,6.RS,11.RA,16.D:D:::Store Half Word with Update
+       unsigned_word EA;
+       if (RA == 0)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + EXTS(D);
+       STORE(EA, 2, *rS);
+       *rA = EA;
+0.31,6.RS,11.RA,16.RB,21.439,31./:X:::Store Half Word with Update Indexed
+       unsigned_word EA;
+       if (RA == 0)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + *rB;
+       STORE(EA, 2, *rS);
+       *rA = EA;
+
+0.36,6.RS,11.RA,16.D:D:::Store Word
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + EXTS(D);
+       STORE(EA, 4, *rS);
+0.31,6.RS,11.RA,16.RB,21.151,31./:X:::Store Word Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       STORE(EA, 4, *rS);
+0.37,6.RS,11.RA,16.D:D:::Store Word with Update
+       unsigned_word EA;
+       if (RA == 0)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + EXTS(D);
+       STORE(EA, 4, *rS);
+       *rA = EA;
+0.31,6.RS,11.RA,16.RB,21.183,31./:X:::Store Word with Update Indexed
+       unsigned_word EA;
+       if (RA == 0)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + *rB;
+       STORE(EA, 4, *rS);
+       *rA = EA;
+
+0.62,6.RS,11.RA,16.DS,30.0:DS:64::Store Doubleword
+#      unsigned_word b;
+#      unsigned_word EA;
+#      if (RA == 0) b = 0;
+#      else         b = *rA;
+#      EA = b + EXTS(DS_0b00);
+#      STORE(EA, 8, *rS);
+0.31,6.RS,11.RA,16.RB,21.149,31./:X:64::Store Doubleword Indexed
+#      unsigned_word b;
+#      unsigned_word EA;
+#      if (RA == 0) b = 0;
+#      else         b = *rA;
+#      EA = b + *rB;
+#      STORE(EA, 8, *rS);
+0.62,6.RS,11.RA,16.DS,30.1:DS:64::Store Doubleword with Update
+#      unsigned_word EA;
+#      if (RA == 0)
+#        program_interrupt(processor, cia
+#                          illegal_instruction_program_interrupt);
+#      EA = *rA + EXTS(DS_0b00);
+#      STORE(EA, 8, *rS);
+#      *rA = EA;
+0.31,6.RS,11.RA,16.RB,21.181,31./:X:64::Store Doubleword with Update Indexed
+#      unsigned_word EA;
+#      if (RA == 0)
+#        program_interrupt(processor, cia
+#                          illegal_instruction_program_interrupt);
+#      EA = *rA + *rB;
+#      STORE(EA, 8, *rS);
+#      *rA = EA;
+
+
+#
+# I.3.3.4 Fixed-Point Load and Store with Byte Reversal Instructions
+#
+
+0.31,6.RT,11.RA,16.RB,21.790,31./:X:::Load Halfword Byte-Reverse Indexed
+#      unsigned_word b;
+#      unsigned_word EA;
+#      if (RA == 0) b = 0;
+#      else         b = *rA;
+#      EA = b + *rB;
+#      *rT = SWAP2(MEM(unsigned, EA, 2));
+0.31,6.RT,11.RA,16.RB,21.534,31./:X:::Load Word Byte-Reverse Indexed
+#      unsigned_word b;
+#      unsigned_word EA;
+#      if (RA == 0) b = 0;
+#      else         b = *rA;
+#      EA = b + *rB;
+#      *rT = SWAP4(MEM(unsigned, EA, 4));
+
+0.31,6.RS,11.RA,16.RB,21.918,31./:X:::Store Half Word Byte-Reversed Indexed
+#      unsigned_word b;
+#      unsigned_word EA;
+#      if (RA == 0) b = 0;
+#      else         b = *rA;
+#      EA = b + *rB;
+#      STORE(EA, 2, SWAP2(*rS));
+0.31,6.RS,11.RA,16.RB,21.662,31./:X:::Store Word Byte-Reversed Indexed
+#      unsigned_word b;
+#      unsigned_word EA;
+#      if (RA == 0) b = 0;
+#      else         b = *rA;
+#      EA = b + *rB;
+#      STORE(EA, 4, SWAP4(*rS));
+
+
+#
+# I.3.3.5 Fixed-Point Load and Store Multiple Instrctions
+#
+
+0.46,6.RT,11.RA,16.D:D:be::Load Multiple Word
+0.47,6.RS,11.RA,16.D:D:be::Store Multiple Word
+
+
+#
+# I.3.3.6 Fixed-Point Move Assist Instructions
+#
+
+0.31,6.RT,11.RA,16.NB,21.597,31./:X:be::Load String Word Immediate
+0.31,6.RT,11.RA,16.RB,21.533,31./:X:be::Load String Word Indexed
+
+0.31,6.RS,11.RA,16.NB,21.725,31./:X:be::Store String Word Immedate
+0.31,6.RS,11.RA,16.RB,21.661,31./:X:be::Store String Word Indexed
+
+
+#
+# I.3.3.7 Storage Synchronization Instructions
+#
+# HACK: Rather than monitor addresses looking for a reason
+#       to cancel a reservation.  This code instead keeps
+#      a copy of the data read from memory.  Before performing
+#      a store, the memory area is checked to see if it has
+#      been changed.
+0.31,6.RT,11.RA,16.RB,21.20,31./:X:::Load Word And Reserve Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       RESERVE = 1;
+       RESERVE_ADDR = real_addr(EA, 1/*is-read?*/);
+       RESERVE_DATA = MEM(unsigned, EA, 4);
+       *rT = RESERVE_DATA;
+0.31,6.RT,11.RA,16.RB,21.84,31./:X:64::Load Doubleword And Reserve Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       RESERVE = 1;
+       RESERVE_ADDR = real_addr(EA, 1/*is-read?*/);
+       RESERVE_DATA = MEM(unsigned, EA, 8);
+       *rT = RESERVE_DATA;
+
+0.31,6.RS,11.RA,16.RB,21.150,31.1:X:::Store Word Conditional Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       if (RESERVE) {
+         if (RESERVE_ADDR == real_addr(EA, 0/*is-read?*/)
+             && /*HACK*/ RESERVE_DATA == MEM(unsigned, EA, 4)) {
+           STORE(EA, 4, *rS);
+           CR_SET_XER_SO(0, cr_i_zero);
+         }
+         else {
+           /* ment to randomly to store, we never do! */       
+           CR_SET_XER_SO(0, 0);
+         }
+         RESERVE = 0;
+       }
+       else {
+         CR_SET_XER_SO(0, 0);
+       }
+0.31,6.RS,11.RA,16.RB,21.214,31.1:X:64::Store Doubleword Conditional Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       if (RESERVE) {
+         if (RESERVE_ADDR == real_addr(EA, 0/*is-read?*/)
+             && /*HACK*/ RESERVE_DATA == MEM(unsigned, EA, 8)) {
+           STORE(EA, 8, *rS);
+           CR_SET_XER_SO(0, cr_i_zero);
+         }
+         else {
+           /* ment to randomly to store, we never do */        
+           CR_SET_XER_SO(0, 0);
+         }
+         RESERVE = 0;
+       }
+       else {
+         CR_SET_XER_SO(0, 0);
+       }
+
+0.31,6./,11./,16./,21.598,31./:X::sync:Synchronize
+       /* do nothing */
+
+
+#
+# I.3.3.9 Fixed-Point Arithmetic Instructions
+#
+
+0.14,6.RT,11.RA,16.SI:D:T::Add Immediate
+       if (RA_is_0) *rT = EXTS(SI);
+       else         *rT = *rA + EXTS(SI);
+0.15,6.RT,11.RA,16.SI:D:::Add Immediate Shifted
+       if (RA_is_0) *rT = EXTS(SI) << 16;
+       else         *rT = *rA + (EXTS(SI) << 16);
+0.31,6.RT,11.RA,16.RB,21.OE,22.266,31.Rc:XO:::Add
+       ALU_BEGIN(*rA);
+       ALU_ADD(*rB);
+       ALU_END(*rT, 0/*CA*/, OE, Rc);
+0.31,6.RT,11.RA,16.RB,21.OE,22.40,31.Rc:XO:::Subtract From
+       ALU_BEGIN(*rA);
+       ALU_NOT;
+       ALU_ADD(*rB);
+       ALU_ADD(1);
+       ALU_END(*rT, 0/*CA*/, OE, Rc);
+0.12,6.RT,11.RA,16.SI:D:::Add Immediate Carrying
+       ALU_BEGIN(*rA);
+       ALU_ADD(EXTS(SI));
+       ALU_END(*rT, 1/*CA*/, 0/*OE*/, 0/*Rc*/);
+0.13,6.RT,11.RA,16.SI:D:::Add Immediate Carrying and Record
+       ALU_BEGIN(*rA);
+       ALU_ADD(EXTS(SI));
+       ALU_END(*rT, 1/*CA*/, 0/*OE*/, 1/*Rc*/);
+0.8,6.RT,11.RA,16.SI:D:::Subtract From Immediate Carrying
+       ALU_BEGIN(*rA);
+       ALU_NOT;
+       ALU_ADD(EXTS(SI));
+       ALU_ADD(1);
+       ALU_END(*rT, 1/*CA*/, 0/*OE*/, 0/*Rc*/);
+0.31,6.RT,11.RA,16.RB,21.OE,22.10,31.Rc:XO:::Add Carrying
+       ALU_BEGIN(*rA);
+       ALU_ADD(*rB);
+       ALU_END(*rT, 1/*CA*/, OE, Rc);
+0.31,6.RT,11.RA,16.RB,21.OE,22.8,31.Rc:XO:::Subtract From Carrying
+       /* RT <- ~RA + RB + 1 === RT <- RB - RA */
+       ALU_BEGIN(*rA);
+       ALU_NOT;
+       ALU_ADD(*rB);
+       ALU_ADD(1);
+       ALU_END(*rT, 1/*CA*/, OE, Rc);
+0.31,6.RT,11.RA,16.RB,21.OE,22.138,31.Rc:XO:::Add Extended
+       ALU_BEGIN(*rA);
+       ALU_ADD(*rB);
+       ALU_ADD_CA;
+       ALU_END(*rT, 1/*CA*/, OE, Rc);
+0.31,6.RT,11.RA,16.RB,21.OE,22.136,31.Rc:XO:::Subtract From Extended
+       ALU_BEGIN(*rA);
+       ALU_NOT;
+       ALU_ADD(*rB);
+       ALU_ADD_CA;
+       ALU_END(*rT, 1/*CA*/, OE, Rc);
+0.31,6.RT,11.RA,16./,21.OE,22.234,31.Rc:XO:::Add to Minus One Extended
+#      ALU_BEGIN(*rA);
+#      ALU_ADD_CA;
+#      ALU_SUB(1);
+#      ALU_END(*rT, 1/*CA*/, OE, Rc);
+0.31,6.RT,11.RA,16./,21.OE,22.232,31.Rc:XO:::Subtract From Minus One Extended
+#      ALU_BEGIN(*rA);
+#      ALU_NOT;
+#      ALU_ADD_CA;
+#      ALU_SUB(1);
+#      ALU_END(*rT, 1/*CA*/, OE, Rc);
+0.31,6.RT,11.RA,16./,21.OE,22.202,31.Rc:XO::addze:Add to Zero Extended
+       ALU_BEGIN(*rA);
+       ALU_ADD_CA;
+       ALU_END(*rT, 1/*CA*/, OE, Rc);
+0.31,6.RT,11.RA,16./,21.OE,22.200,31.Rc:XO:::Subtract from Zero Extended
+       ALU_BEGIN(*rA);
+       ALU_NOT;
+       ALU_ADD_CA;
+       ALU_END(*rT, 1/*CA*/, OE, Rc);
+0.31,6.RT,11.RA,16./,21.OE,22.104,31.Rc:XO:::Negate
+       ALU_BEGIN(*rA);
+       ALU_NOT;
+       ALU_ADD(1);
+       ALU_END(*rT,0/*CA*/,OE,Rc);
+0.7,6.RT,11.RA,16.SI:D::mulli:Multiply Low Immediate
+       signed_word prod = *rA * EXTS(SI);
+       *rT = prod;
+0.31,6.RT,11.RA,16.RB,21.OE,22.233,31.Rc:D:64::Multiply Low Doubleword
+0.31,6.RT,11.RA,16.RB,21.OE,22.235,31.Rc:XO::mullw:Multiply Low Word
+       signed64 a = (signed32)(*rA);
+       signed64 b = (signed32)(*rB);
+       signed64 prod = a * b;
+       signed_word t = prod;
+       *rT = *rA * *rB;
+       if (t != prod && OE)
+         XER |= (xer_overflow | xer_summary_overflow);
+       CR0_COMPARE(t, 0, Rc);
+0.31,6.RT,11.RA,16.RB,21./,22.73,31.Rc:XO:64::Multiply High Doubleword
+0.31,6.RT,11.RA,16.RB,21./,22.75,31.Rc:XO::mulhw:Multiply High Word
+       signed64 a = (signed32)(*rA);
+       signed64 b = (signed32)(*rB);
+       signed64 prod = a * b;
+       signed_word t = EXTRACTED64(prod, 0, 31);
+       *rT = t;
+       CR0_COMPARE(t, 0, Rc);
+0.31,6.RT,11.RA,16.RB,21./,22.9,31.Rc:XO:64::Multiply High Doubleword Unsigned
+0.31,6.RT,11.RA,16.RB,21./,22.11,31.Rc:XO::milhwu:Multiply High Word Unsigned
+       unsigned64 a = (unsigned32)(*rA);
+       unsigned64 b = (unsigned32)(*rB);
+       unsigned64 prod = a * b;
+       signed_word t = EXTRACTED64(prod, 0, 31);
+       *rT = t;
+       CR0_COMPARE(t, 0, Rc);
+0.31,6.RT,11.RA,16.RB,21.OE,22.489,31.Rc:XO:64::Divide Doubleword
+0.31,6.RT,11.RA,16.RB,21.OE,22.491,31.Rc:XO::divw:Divide Word
+       signed64 dividend = (signed32)(*rA);
+       signed64 divisor = (signed32)(*rB);
+       if (divisor == 0 /* nb 0x8000..0 is sign extended */
+           || (dividend == 0x80000000 && divisor == -1)) {
+         if (OE)
+           XER |= (xer_overflow | xer_summary_overflow);
+         CR0_COMPARE(0, 0, Rc);
+       }
+       else {
+         signed64 quotent = dividend / divisor;
+         *rT = quotent;
+         CR0_COMPARE((signed_word)quotent, 0, Rc);
+       }
+0.31,6.RT,11.RA,16.RB,21.OE,22.457,31.Rc:XO:64::Divide Doubleword Unsigned
+0.31,6.RT,11.RA,16.RB,21.OE,22.459,31.Rc:XO::divwu:Divide Word Unsigned
+       unsigned64 dividend = (unsigned32)(*rA);
+       unsigned64 divisor = (unsigned32)(*rB);
+       if (divisor == 0) {
+         if (OE)
+           XER |= (xer_overflow | xer_summary_overflow);
+         CR0_COMPARE(0, 0, Rc);
+       }
+       else {
+         unsigned64 quotent = dividend / divisor;
+         *rT = quotent;
+         CR0_COMPARE((signed_word)quotent, 0, Rc);
+       }
+
+
+#
+# I.3.3.10 Fixed-Point Compare Instructions
+#
+
+0.11,6.BF,9./,10.L,11.RA,16.SI:D:::Compare Immediate
+       if (!is_64bit_mode && L)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       else {
+         signed_word a;
+         signed_word b = EXTS(SI);
+         if (L == 0)
+           a = EXTENDED(*rA);
+         else
+           a = *rA;
+         CR_COMPARE(BF, a, b);
+       }
+0.31,6.BF,9./,10.L,11.RA,16.RB,21.0,31./:X:::Compare
+       if (!is_64bit_mode && L)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       else {
+         signed_word a;
+         signed_word b;
+         if (L == 0) {
+           a = EXTENDED(*rA);
+           b = EXTENDED(*rB);
+         }
+         else {
+           a = *rA;
+           b = *rB;
+         }
+         CR_COMPARE(BF, a, b);
+       }
+0.10,6.BF,9./,10.L,11.RA,16.UI:D:::Compare Logical Immediate
+       if (!is_64bit_mode && L)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       else {
+         unsigned_word a;
+         unsigned_word b = UI;
+         if (L == 0)
+           a = MASKED(*rA, 32, 63);
+         else
+           a = *rA;
+         CR_COMPARE(BF, a, b);
+       }
+0.31,6.BF,9./,10.L,11.RA,16.RB,21.32,31./:X:::Compare Logical
+       if (!is_64bit_mode && L)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       else {
+         unsigned_word a;
+         unsigned_word b;
+         if (L == 0) {
+           a = MASKED(*rA, 32, 63);
+           b = MASKED(*rB, 32, 63);
+         }
+         else {
+           a = *rA;
+           b = *rB;
+         }
+         CR_COMPARE(BF, a, b);
+       }
+
+
+#
+# I.3.3.11 Fixed-Point Trap Instructions
+#
+
+0.2,6.TO,11.RA,16.SI:D:64::Trap Doubleword Immediate
+       if (!is_64bit_mode)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       else {
+         signed_word a = *rA;
+         signed_word b = EXTS(SI);
+         if ((a < b && TO{0})
+             || (a > b && TO{1})
+             || (a == b && TO{2})
+             || ((unsigned_word)a < (unsigned_word)b && TO{3})
+             || ((unsigned_word)a > (unsigned_word)b && TO{4})
+             )
+           program_interrupt(processor, cia,
+                             trap_program_interrupt);
+       }
+0.3,6.TO,11.RA,16.SI:D:::Trap Word Immediate
+       signed_word a = EXTENDED(*rA);
+       signed_word b = EXTS(SI);
+       if ((a < b && TO{0})
+           || (a > b && TO{1})
+           || (a == b && TO{2})
+           || ((unsigned_word)a < (unsigned_word)b && TO{3})
+           || ((unsigned_word)a > (unsigned_word)b && TO{4})
+           )
+         program_interrupt(processor, cia,
+                           trap_program_interrupt);
+0.31,6.TO,11.RA,16.RB,21.68,31./:X:64::Trap Doubleword
+       if (!is_64bit_mode)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       else {
+         signed_word a = *rA;
+         signed_word b = *rB;
+         if ((a < b && TO{0})
+             || (a > b && TO{1})
+             || (a == b && TO{2})
+             || ((unsigned_word)a < (unsigned_word)b && TO{3})
+             || ((unsigned_word)a > (unsigned_word)b && TO{4})
+             )
+           program_interrupt(processor, cia,
+                             trap_program_interrupt);
+       }
+0.31,6.TO,11.RA,16.RB,21.4,31./:X:::Trap Word
+       signed_word a = EXTENDED(*rA);
+       signed_word b = EXTENDED(*rB);
+       if (TO == 12 && rA == rB) {
+         ITRACE(trace_breakpoint, ("breakpoint\n"));
+         cpu_halt(processor, cia, was_trap, 0);
+       }
+       else if ((a < b && TO{0})
+           || (a > b && TO{1})
+           || (a == b && TO{2})
+           || ((unsigned_word)a < (unsigned_word)b && TO{3})
+           || ((unsigned_word)a > (unsigned_word)b && TO{4})
+           )
+         program_interrupt(processor, cia,
+                           trap_program_interrupt);
+
+#
+# I.3.3.12 Fixed-Point Logical Instructions
+#
+
+0.28,6.RS,11.RA,16.UI:D:::AND Immediate
+       *rA = *rS & UI;
+       CR0_COMPARE(*rA, 0, 1/*Rc*/);
+0.29,6.RS,11.RA,16.UI:D:::AND Immediate Shifted
+       *rA = *rS & (UI << 16);
+       CR0_COMPARE(*rA, 0, 1/*Rc*/);
+0.24,6.RS,11.RA,16.UI:D:::OR Immediate
+       *rA = *rS | UI;
+0.25,6.RS,11.RA,16.UI:D:::OR Immediate Shifted
+       *rA = *rS | (UI << 16);
+0.26,6.RS,11.RA,16.UI:D:::XOR Immediate
+       *rA = *rS ^ UI;
+0.27,6.RS,11.RA,16.UI:D:::XOR Immediate Shifted
+       *rA = *rS ^ (UI << 16);
+0.31,6.RS,11.RA,16.RB,21.28,31.Rc:X:::AND
+       *rA = *rS & *rB;
+       CR0_COMPARE(*rA, 0, Rc);
+0.31,6.RS,11.RA,16.RB,21.444,31.Rc:X:::OR
+       *rA = *rS | *rB;
+       CR0_COMPARE(*rA, 0, Rc);
+0.31,6.RS,11.RA,16.RB,21.316,31.Rc:X:::XOR
+       *rA = *rS ^ *rB;
+       CR0_COMPARE(*rA, 0, Rc);
+0.31,6.RS,11.RA,16.RB,21.476,31.Rc:X:::NAND
+       *rA = ~(*rS & *rB);
+       CR0_COMPARE(*rA, 0, Rc);
+0.31,6.RS,11.RA,16.RB,21.124,31.Rc:X:::NOR
+       *rA = ~(*rS | *rB);
+       CR0_COMPARE(*rA, 0, Rc);
+0.31,6.RS,11.RA,16.RB,21.284,31.Rc:X:::Equivalent
+#      *rA = ~(*rS ^ *rB); /* A === B */
+#      CR0_COMPARE(*rA, 0, Rc);
+0.31,6.RS,11.RA,16.RB,21.60,31.Rc:X:::AND with Complement
+       *rA = *rS & ~*rB;
+       CR0_COMPARE(*rA, 0, Rc);
+0.31,6.RS,11.RA,16.RB,21.412,31.Rc:X:::OR with Complement
+       *rA = *rS | ~*rB;
+       CR0_COMPARE(*rA, 0, Rc);
+0.31,6.RS,11.RA,16./,21.954,31.Rc:X::extsb:Extend Sign Byte
+       *rA = (signed_word)(signed8)*rS;
+       CR0_COMPARE(*rA, 0, Rc);
+0.31,6.RS,11.RA,16./,21.922,31.Rc:X::extsh:Extend Sign Half Word
+       *rA = (signed_word)(signed16)*rS;
+       CR0_COMPARE(*rA, 0, Rc);
+0.31,6.RS,11.RA,16./,21.986,31.Rc:X:64::Extend Sign Word
+#      *rA = (signed_word)(signed32)*rS;
+#      CR0_COMPARE(*rA, 0, Rc);
+0.31,6.RS,11.RA,16./,21.58,31.Rc:X:64::Count Leading Zeros Doubleword
+#      int count = 0;
+#      unsigned64 mask = BIT64(0);
+#      unsigned64 source = *rS;
+#      while (!(source & mask) && mask != 0) {
+#        mask >>= 1;
+#        count++;
+#      }
+#      *rA = count;
+#      CR0_COMPARE(count, 0, Rc); /* FIXME - is this correct */
+0.31,6.RS,11.RA,16./,21.26,31.Rc:X:::Count Leading Zeros Word
+       int count = 0;
+       unsigned32 mask = BIT32(0);
+       unsigned32 source = *rS;
+       while (!(source & mask) && mask != 0) {
+         mask >>= 1;
+         count++;
+       }
+       *rA = count;
+       CR0_COMPARE(count, 0, Rc); /* FIXME - is this correct */
+
+
+#
+# I.3.3.13 Fixed-Point Rotate and Shift Instructions
+#
+
+0.30,6.RS,11.RA,16.sh_0_4,21.mb,27.0,30.sh_5,31.Rc:MD:64::Rotate Left Doubleword Immediate then Clear Left
+#      long n = (sh_5 << 4) | sh_0_4;
+#      unsigned_word r = ROTL64(*rS, n);
+#      long b = (mb_5 << 4) | mb_0_4;
+#      unsigned_word m = MASK(b, 63);
+#      signed_word result = r & m;
+#      *rA = result;
+#      CR0_COMPARE(result, 0, Rc); /* FIXME - is this correct */
+0.30,6.RS,11.RA,16.sh_0_4,21.me,27.1,30.sh_5,31.Rc:MD:64::Rotate Left Doubleword Immediate then Clear Right
+#      long n = (sh_5 << 4) | sh_0_4;
+#      unsigned_word r = ROTL64(*rS, n);
+#      long e = (me_5 << 4) | me_0_4;
+#      unsigned_word m = MASK(0, e);
+#      signed_word result = r & m;
+#      *rA = result;
+#      CR0_COMPARE(result, 0, Rc); /* FIXME - is this correct */
+0.30,6.RS,11.RA,16.sh_0_4,21.mb,27.2,30.sh_5,31.Rc:MD:64::Rotate Left Doubleword Immediate then Clear
+#      long n = (sh_5 << 4) | sh_0_4;
+#      unsigned_word r = ROTL64(*rS, n);
+#      long b = (mb_5 << 4) | mb_0_4;
+#      unsigned_word m = MASK(0, (64-n));
+#      signed_word result = r & m;
+#      *rA = result;
+#      CR0_COMPARE(result, 0, Rc); /* FIXME - is this correct */
+
+0.21,6.RS,11.RA,16.SH,21.MB,26.ME,31.Rc:M:::Rotate Left Word Immediate then AND with Mask
+       long n = SH;
+       unsigned32 s = *rS;
+       unsigned32 r = ROTL32(s, n);
+       unsigned32 m = MASK(MB+32, ME+32);
+       signed_word result = r & m;
+       *rA = result;
+       CR0_COMPARE(result, 0, Rc);
+       ITRACE(trace_alu,
+              ("n=%d, s=0x%x, r=0x%x, m=0x%x, result=0x%x, cr=0x%x\n",
+               n, s, r, m, result, CR));
+
+0.30,6.RS,11.RA,16.RB,21.mb,27.8,31.Rc:MDS:64::Rotate Left Doubleword then Clear Left
+#      long n = MASKED(*rB, 58, 63);
+#      unsigned_word r = ROTL64(*rS, n);
+#      long b = (mb_5 << 4) | mb_0_4;
+#      unsigned_word m = MASK(b, 63);
+#      signed_word result = r & m;
+#      *rA = result;
+#      CR0_COMPARE(result, 0, Rc);
+0.30,6.RS,11.RA,16.RB,21.me,27.9,31.Rc:MDS:64::Rotate Left Doubleword then Clear Right
+#      long n = MASKED(*rB, 58, 63);
+#      unsigned_word r = ROTL64(*rS, n);
+#      long e = (me_5 << 4) | me_0_4;
+#      unsigned_word m = MASK(0, e);
+#      signed_word result = r & m;
+#      *rA = result;
+#      CR0_COMPARE(result, 0, Rc);
+
+0.23,6.RS,11.RA,16.RB,21.MB,26.ME,31.Rc:M:::Rotate Left Word then AND with Mask
+#      long n = MASKED(*rB, 59, 63);
+#      unsigned32 r = ROTL32(*rS, n);
+#      unsigned32 m = MASK(MB+32, ME+32);
+#      signed_word result = r & m;
+#      *rA = result;
+#      CR0_COMPARE(result, 0, Rc);
+0.30,6.RS,11.RA,16.sh_0_4,21.mb,27.3,30.sh_5,31.Rc:MD:64::Rotate Left Doubleword Immediate then Mask Insert
+#      long n = (sh_5 << 4) | sh_0_4;
+#      unsigned_word r = ROTL64(*rS, n);
+#      long b = (mb_5 << 4) | mb_0_4;
+#      unsigned_word m = MASK(b, (64-n));
+#      signed_word result = (r & m) | (*rA & ~m)
+#      *rA = result;
+#      CR0_COMPARE(result, 0, Rc);
+0.20,6.RS,11.RA,16.SH,21.MB,26.ME,31.Rc:M::rlwimi:Rotate Left Word Immediate then Mask Insert
+       long n = SH;
+       unsigned32 r = ROTL32(*rS, n);
+       unsigned32 m = MASK(MB+32, ME+32);
+       signed_word result = (r & m) | (*rA & ~m);
+       *rA = result;
+       ITRACE(trace_alu, (": n=%d *rS=0x%x r=0x%x m=0x%x result=0x%x\n",
+                          n, *rS, r, m, result));
+       CR0_COMPARE(result, 0, Rc);
+
+
+0.31,6.RS,11.RA,16.RB,21.27,31.Rc:X:64::Shift Left Doubleword
+0.31,6.RS,11.RA,16.RB,21.24,31.Rc:X:::Shift Left Word
+       int n = MASKED(*rB, 59, 63);
+       unsigned32 source = *rS;
+       signed_word shifted;
+       if (n < 32)
+         shifted = (source << n);
+       else
+         shifted = 0;
+       *rA = shifted;
+       CR0_COMPARE(shifted, 0, Rc);
+       ITRACE(trace_alu,
+              ("n=%d, source=0x%x, shifted=0x%x\n",
+               n, source, shifted));
+0.31,6.RS,11.RA,16.RB,21.539,31.Rc:X:64::Shift Right Doubleword
+0.31,6.RS,11.RA,16.RB,21.536,31.Rc:X:::Shift Right Word
+       int n = MASKED(*rB, 59, 63);
+       unsigned32 source = *rS;
+       signed_word shifted;
+       if (n < 32)
+         shifted = (source >> n);
+       else
+         shifted = 0;
+       *rA = shifted;
+       CR0_COMPARE(shifted, 0, Rc);
+       ITRACE(trace_alu, \
+              ("n=%d, source=0x%x, shifted=0x%x\n",
+               n, source, shifted));
+
+0.31,6.RS,11.RA,16.sh_0_4,21.413,30.sh_5,31.Rc:XS:64::Shift Right Algebraic Doubleword Immediate
+0.31,6.RS,11.RA,16.SH,21.824,31.Rc:X:::Shift Right Algebraic Word Immediate
+       int n = SH;
+       signed_word r = ROTL32(*rS, /*64*/32-n);
+       signed_word m = MASK(n+32, 63);
+       int S = MASKED(*rS, 32, 32);
+       signed_word shifted = (r & m) | (S ? ~m : 0);
+       *rA = shifted;
+       if (S && ((r & ~m) & MASK(32, 63)) != 0)
+         XER |= xer_carry;
+       else
+         XER &= ~xer_carry;
+       CR0_COMPARE(shifted, 0, Rc);
+0.31,6.RS,11.RA,16.RB,21.794,31.Rc:X:64::Shift Right Algebraic Doubleword
+0.31,6.RS,11.RA,16.RB,21.792,31.Rc:X:::Shift Right Algebraic Word
+       int n = MASKED(*rB, 58, 63);
+       int shift = (n >= 31 ? 31 : n);
+       signed32 source = (signed32)*rS; /* signed to keep sign bit */
+       signed32 shifted = source >> shift;
+       unsigned32 mask = ((unsigned32)-1) >> (31-shift);
+       *rA = (signed_word)shifted; /* if 64bit will sign extend */
+       if (source < 0 && (source & mask))
+         XER |= xer_carry;
+       else
+         XER &= ~xer_carry;
+       CR0_COMPARE(shifted, 0, Rc);
+
+
+#
+# I.3.3.14 Move to/from System Register Instructions
+#
+
+0.31,6.RS,11.spr,21.467,31./:XFX:::Move to Special Purpose Register
+       int n = (spr{5:9} << 5) | spr{0:4};
+       if (spr{0} && IS_PROBLEM_STATE(processor))
+         program_interrupt(processor, cia,
+                           privileged_instruction_program_interrupt);
+       else if (!spr_is_valid(n)
+                || spr_is_readonly(n))
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       else {
+         spreg new_val = (spr_length(n) == 64
+                          ? *rS
+                          : MASKED(*rS, 32, 63));
+         /* HACK - time base registers need to be updated immediatly */
+         if (WITH_TIME_BASE) {
+           signed64 time_base;
+           switch (n) {
+           case spr_tbu:
+             cpu_set_time_base(processor,
+                               (MASKED64(cpu_get_time_base(processor),
+                                         32, 63)
+                                | ((signed64)new_val << 32)));
+             break;
+           case spr_tbl:
+             cpu_set_time_base(processor,
+                               (MASKED64(cpu_get_time_base(processor),
+                                         32, 63)
+                                | ((signed64)new_val << 32)));
+             break;
+           case spr_dec:
+             cpu_set_decrementer(processor, new_val);
+             break;
+           default:
+             SPREG(n) = new_val;
+             break;
+           }
+         }
+         else {
+           SPREG(n) = new_val;
+         }
+       }
+0.31,6.RT,11.spr,21.339,31./:XFX:uea::Move from Special Purpose Register
+       int n = (spr{5:9} << 5) | spr{0:4};
+       if (spr{0} && IS_PROBLEM_STATE(processor))
+         program_interrupt(processor, cia,
+                           privileged_instruction_program_interrupt);
+       else if (!spr_is_valid(n))
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       else {
+         /* HACK - some SPR's need to get their value extracted specially */
+         *rT = SPREG(n);
+       }
+0.31,6.RS,11./,12.FXM,20./,21.144,31./:XFX::mtfcr:Move to Condition Register Fields
+       if (FXM == 0xff) {
+         CR = *rS;
+       }
+       else {
+         unsigned_word mask = 0;
+         unsigned_word f;
+         for (f = 0; f < 8; f++) {
+           if (FXM & (0x80 >> f))
+             mask |= (0xf << 4*(7-f));
+         }
+         CR = (MASKED(*rS, 32, 63) & mask) | (CR & ~mask);
+       }
+0.31,6.BF,9./,11./,16./,21.512,31./:X:::Move to Condition Register from XER
+0.31,6.RT,11./,16./,21.19,31./:X:::Move From Condition Register
+       *rT = (unsigned32)CR;
+
+#
+# I.4.6.2 Floating-Point Load Instructions
+#
+
+0.48,6.FRT,11.RA,16.D:D:f:lfs:Load Floating-Point Single
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + EXTS(D);
+       *frT = DOUBLE(MEM(unsigned, EA, 4));
+0.31,6.FRT,11.RA,16.RB,21.535,31./:X:f::Load Floating-Point Single Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       *frT = DOUBLE(MEM(unsigned, EA, 4));
+0.49,6.FRT,11.RA,16.D:D:f::Load Floating-Point Single with Update
+       unsigned_word EA;
+       if (RA == 0)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + EXTS(D);
+       *frT = DOUBLE(MEM(unsigned, EA, 4));
+       *rA = EA;
+0.31,6.FRT,11.RA,16.RB,21.576,31./:X:f::Load Floating-Point Single with Update Indexed
+       unsigned_word EA;
+       if (RA == 0)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + *rB;
+       *frT = DOUBLE(MEM(unsigned, EA, 4));
+       *rA = EA;
+
+0.50,6.FRT,11.RA,16.D:D:f::Load Floating-Point Double
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + EXTS(D);
+       *frT = MEM(unsigned, EA, 8);
+0.31,6.FRT,11.RA,16.RB,21.599,31./:X:f::Load Floating-Point Double Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       *frT = MEM(unsigned, EA, 8);
+0.51,6.FRT,11.RA,16.D:D:f::Load Floating-Point Double with Update
+       unsigned_word EA;
+       if (RA == 0)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + EXTS(D);
+       *frT = MEM(unsigned, EA, 8);
+       *rA = EA;
+0.31,6.FRT,11.RA,16.RB,21.631,31./:X:f::Load Floating-Point Double with Update Indexed
+       unsigned_word EA;
+       if (RA == 0)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + *rB;
+       *frT = MEM(unsigned, EA, 8);
+       *rA = EA;
+
+
+#
+# I.4.6.3 Floating-Point Store Instructions
+#
+
+0.52,6.FRS,11.RA,16.D:D:f::Store Floating-Point Single
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + EXTS(D);
+       STORE(EA, 4, SINGLE(*frS));
+0.31,6.FRS,11.RA,16.RB,21.663,31./:X:f::Store Floating-Point Single Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       STORE(EA, 4, SINGLE(*frS));
+0.53,6.FRS,11.RA,16.D:D:f::Store Floating-Point Single with Update
+       unsigned_word EA;
+       if (RA == 0)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + EXTS(D);
+       STORE(EA, 4, SINGLE(*frS));
+       *rA = EA;
+0.31,6.FRS,11.RA,16.RB,21.695,31./:X:f::Store Floating-Point Single with Update Indexed
+       unsigned_word EA;
+       if (RA == 0)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + *rB;
+       STORE(EA, 4, SINGLE(*frS));
+       *rA = EA;
+
+0.54,6.FRS,11.RA,16.D:D:f::Store Floating-Point Double
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + EXTS(D);
+       STORE(EA, 8, *frS);
+0.31,6.FRS,11.RA,16.RB,21.727,31./:X:f::Store Floating-Point Double Indexed
+       unsigned_word b;
+       unsigned_word EA;
+       if (RA == 0) b = 0;
+       else         b = *rA;
+       EA = b + *rB;
+       STORE(EA, 8, *frS);
+0.55,6.FRS,11.RA,16.D:D:f::Store Floating-Point Double with Update
+       unsigned_word EA;
+       if (RA == 0)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + EXTS(D);
+       STORE(EA, 8, *frS);
+       *rA = EA;
+0.31,6.FRS,11.RA,16.RB,21.759,31./:X:f::Store Floating-Point Double with Update Indexed
+       unsigned_word EA;
+       if (RA == 0)
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+       EA = *rA + *rB;
+       STORE(EA, 8, *frS);
+       *rA = EA;
+
+
+#
+# I.4.6.4 Floating-Point Move Instructions
+#
+
+0.63,6.FRT,11./,16.FRB,21.72,31.Rc:X:f::Floating Move Register
+       *frT = *frB;
+       CR1_UPDATE(Rc);
+0.63,6.FRT,11./,16.FRB,21.40,31.Rc:X:f::Floating Negate
+       *frT = *frB ^ BIT64(0);
+       CR1_UPDATE(Rc);
+0.63,6.FRT,11./,16.FRB,21.264,31.Rc:X:f::Floating Absolute Value
+       *frT = *frB & ~BIT64(0);
+       CR1_UPDATE(Rc);
+0.63,6.FRT,11./,16.FRB,21.136,31.Rc:X:f::Floating Negative Absolute Value
+       *frT = *frB | BIT64(0);
+       CR1_UPDATE(Rc);
+
+
+
+#
+# I.4.6.5 Floating-Point Arithmetic Instructions
+#
+
+0.63,6.FRT,11.FRA,16.FRB,21./,26.21,31.Rc:A:f:fadd:Floating Add
+       FPSCR_BEGIN;
+       if (is_invalid_operation(processor, cia,
+                                *frA, *frB,
+                                fpscr_vxsnan | fpscr_vxisi,
+                                0, /*single?*/
+                                0) /*negate?*/) {
+         invalid_arithemetic_operation(processor, cia,
+                                       frT, *frA, *frB, 0,
+                                       0, /*instruction_is_frsp*/
+                                       0, /*instruction_is_convert_to_64bit*/
+                                       0, /*instruction_is_convert_to_32bit*/
+                                       0); /*single-precision*/
+       }
+       else {
+         /*HACK!*/
+         double s = *(double*)frA + *(double*)frB;
+         *(double*)frT = s;
+       }
+       FPSCR_END(Rc);
+0.59,6.FRT,11.FRA,16.FRB,21./,26.21,31.Rc:A:f:fadds:Floating Add Single
+       FPSCR_BEGIN;
+       if (is_invalid_operation(processor, cia,
+                                *frA, *frB,
+                                fpscr_vxsnan | fpscr_vxisi,
+                                1, /*single?*/
+                                0) /*negate?*/) {
+         invalid_arithemetic_operation(processor, cia,
+                                       frT, *frA, *frB, 0,
+                                       0, /*instruction_is_frsp*/
+                                       0, /*instruction_is_convert_to_64bit*/
+                                       0, /*instruction_is_convert_to_32bit*/
+                                       1); /*single-precision*/
+       }
+       else {
+         /*HACK!*/
+         float s = *(double*)frA + *(double*)frB;
+         *(double*)frT = s;
+       }
+       FPSCR_END(Rc);
+
+0.63,6.FRT,11.FRA,16.FRB,21./,26.20,31.Rc:A:f:fsub:Floating Subtract
+       FPSCR_BEGIN;
+       if (is_invalid_operation(processor, cia,
+                                *frA, *frB,
+                                fpscr_vxsnan | fpscr_vxisi,
+                                0, /*single?*/
+                                1) /*negate?*/) {
+         invalid_arithemetic_operation(processor, cia,
+                                       frT, *frA, *frB, 0,
+                                       0, /*instruction_is_frsp*/
+                                       0, /*instruction_is_convert_to_64bit*/
+                                       0, /*instruction_is_convert_to_32bit*/
+                                       0); /*single-precision*/
+       }
+       else {
+         /*HACK!*/
+         double s = *(double*)frA - *(double*)frB;
+         *(double*)frT = s;
+       }
+       FPSCR_END(Rc);
+0.59,6.FRT,11.FRA,16.FRB,21./,26.20,31.Rc:A:f:fsubs:Floating Subtract Single
+       FPSCR_BEGIN;
+       if (is_invalid_operation(processor, cia,
+                                *frA, *frB,
+                                fpscr_vxsnan | fpscr_vxisi,
+                                1, /*single?*/
+                                1) /*negate?*/) {
+         invalid_arithemetic_operation(processor, cia,
+                                       frT, *frA, *frB, 0,
+                                       0, /*instruction_is_frsp*/
+                                       0, /*instruction_is_convert_to_64bit*/
+                                       0, /*instruction_is_convert_to_32bit*/
+                                       1); /*single-precision*/
+       }
+       else {
+         /*HACK!*/
+         float s = *(double*)frA - *(double*)frB;
+         *(double*)frT = s;
+       }
+       FPSCR_END(Rc);
+
+0.63,6.FRT,11.FRA,16./,21.FRC,26.25,31.Rc:A:f:fmul:Floating Multiply
+       FPSCR_BEGIN;
+       if (is_invalid_operation(processor, cia,
+                                *frA, *frC,
+                                fpscr_vxsnan | fpscr_vximz,
+                                0, /*single?*/
+                                0) /*negate?*/) {
+         invalid_arithemetic_operation(processor, cia,
+                                       frT, *frA, 0, *frC,
+                                       0, /*instruction_is_frsp*/
+                                       0, /*instruction_is_convert_to_64bit*/
+                                       0, /*instruction_is_convert_to_32bit*/
+                                       0); /*single-precision*/
+       }
+       else {
+         /*HACK!*/
+         double s = *(double*)frA * *(double*)frC;
+         *(double*)frT = s;
+       }
+       FPSCR_END(Rc);
+0.59,6.FRT,11.FRA,16./,21.FRC,26.25,31.Rc:A:f:fmuls:Floating Multiply Single
+       FPSCR_BEGIN;
+       if (is_invalid_operation(processor, cia,
+                                *frA, *frC,
+                                fpscr_vxsnan | fpscr_vximz,
+                                1, /*single?*/
+                                0) /*negate?*/) {
+         invalid_arithemetic_operation(processor, cia,
+                                       frT, *frA, 0, *frC,
+                                       0, /*instruction_is_frsp*/
+                                       0, /*instruction_is_convert_to_64bit*/
+                                       0, /*instruction_is_convert_to_32bit*/
+                                       1); /*single-precision*/
+       }
+       else {
+         /*HACK!*/
+         float s = *(double*)frA * *(double*)frC;
+         *(double*)frT = s;
+       }
+       FPSCR_END(Rc);
+
+0.63,6.FRT,11.FRA,16.FRB,21./,26.18,31.Rc:A:f:fdiv:Floating Divide
+       FPSCR_BEGIN;
+       if (is_invalid_operation(processor, cia,
+                                *frA, *frB,
+                                fpscr_vxsnan | fpscr_vxzdz,
+                                0, /*single?*/
+                                0) /*negate?*/) {
+         invalid_arithemetic_operation(processor, cia,
+                                       frT, *frA, *frB, 0,
+                                       0, /*instruction_is_frsp*/
+                                       0, /*instruction_is_convert_to_64bit*/
+                                       0, /*instruction_is_convert_to_32bit*/
+                                       0); /*single-precision*/
+       }
+       else {
+         /*HACK!*/
+         double s = *(double*)frA / *(double*)frB;
+         *(double*)frT = s;
+       }
+       FPSCR_END(Rc);
+0.59,6.FRT,11.FRA,16.FRB,21./,26.18,31.Rc:A:f:fdivs:Floating Divide Single
+       FPSCR_BEGIN;
+       if (is_invalid_operation(processor, cia,
+                                *frA, *frB,
+                                fpscr_vxsnan | fpscr_vxzdz,
+                                1, /*single?*/
+                                0) /*negate?*/) {
+         invalid_arithemetic_operation(processor, cia,
+                                       frT, *frA, *frB, 0,
+                                       0, /*instruction_is_frsp*/
+                                       0, /*instruction_is_convert_to_64bit*/
+                                       0, /*instruction_is_convert_to_32bit*/
+                                       1); /*single-precision*/
+       }
+       else {
+         /*HACK!*/
+         float s = *(double*)frA / *(double*)frB;
+         *(double*)frT = s;
+       }
+       FPSCR_END(Rc);
+
+0.63,6.FRT,11.FRA,16.FRB,21.FRC,26.29,31.Rc:A:f:fmadd:Floating Multiply-Add
+       FPSCR_BEGIN;
+       double product; /*HACK! - incorrectly loosing precision ... */
+       /* compute the multiply */
+       if (is_invalid_operation(processor, cia,
+                                *frA, *frC,
+                                fpscr_vxsnan | fpscr_vximz,
+                                0, /*single?*/
+                                0) /*negate?*/) {
+         invalid_arithemetic_operation(processor, cia,
+                                       (unsigned64*)&product, *frA, 0, *frC,
+                                       0, /*instruction_is_frsp*/
+                                       0, /*instruction_is_convert_to_64bit*/
+                                       0, /*instruction_is_convert_to_32bit*/
+                                       0); /*single-precision*/
+       }
+       else {
+         /*HACK!*/
+         product = *(double*)frA * *(double*)frC;
+       }
+       /* compute the add */
+       if (is_invalid_operation(processor, cia,
+                                product, *frB,
+                                fpscr_vxsnan | fpscr_vxisi,
+                                0, /*single?*/
+                                0) /*negate?*/) {
+         invalid_arithemetic_operation(processor, cia,
+                                       frT, product, *frB, 0,
+                                       0, /*instruction_is_frsp*/
+                                       0, /*instruction_is_convert_to_64bit*/
+                                       0, /*instruction_is_convert_to_32bit*/
+                                       0); /*single-precision*/
+       }
+       else {
+         /*HACK!*/
+         double s = product + *(double*)frB;
+         *(double*)frT = s;
+       }
+       FPSCR_END(Rc);
+0.59,6.FRT,11.FRA,16.FRB,21.FRC,26.29,31.Rc:A:f::Floating Multiply-Add Single
+
+0.63,6.FRT,11.FRA,16.FRB,21.FRC,26.28,31.Rc:A:f::Floating Multiply-Subtract
+0.59,6.FRT,11.FRA,16.FRB,21.FRC,26.28,31.Rc:A:f::Floating Multiply-Subtract Single
+
+0.63,6.FRT,11.FRA,16.FRB,21.FRC,26.31,31.Rc:A:f::Floating Negative Multiply-Add
+0.59,6.FRT,11.FRA,16.FRB,21.FRC,26.31,31.Rc:A:f::Floating Negative Multiply-Add Single
+
+0.63,6.FRT,11.FRA,16.FRB,21.FRC,26.30,31.Rc:A:f::Floating Negative Multiply-Subtract
+0.59,6.FRT,11.FRA,16.FRB,21.FRC,26.30,31.Rc:A:f::Floating Negative Multiply-Subtract Single
+
+
+#
+# I.4.6.6 Floating-Point Rounding and Conversion Instructions
+#
+
+0.63,6.FRT,11./,16.FRB,21.12,31.Rc:X:f::Floating Round to Single-Precision
+       int sign;
+       int exp;
+       unsigned64 frac_grx;
+       /* split off cases for what to do */
+       if (EXTRACTED64(*frB, 1, 11) < 897
+           && EXTRACTED64(*frB, 1, 63) > 0) {
+           if ((FPSCR & fpscr_ue) == 0) goto Disabled_Exponent_Underflow;
+           if ((FPSCR & fpscr_ue) != 0) goto Enabled_Exponent_Underflow;
+       }
+       if (EXTRACTED64(*frB, 1, 11) > 1150
+           && EXTRACTED64(*frB, 1, 11) < 2047) {
+           if ((FPSCR & fpscr_oe) == 0) goto Disabled_Exponent_Overflow;
+           if ((FPSCR & fpscr_oe) != 0) goto Enabled_Exponent_Overflow;
+       }
+       if (EXTRACTED64(*frB, 1, 11) > 896
+           && EXTRACTED64(*frB, 1, 11) < 1151) goto Normal_Operand;
+       if (EXTRACTED64(*frB, 1, 63) == 0) goto Zero_Operand;
+       if (EXTRACTED64(*frB, 1, 11) == 2047) {
+         if (EXTRACTED64(*frB, 12, 63) == 0) goto Infinity_Operand;
+         if (EXTRACTED64(*frB, 12, 12) == 1) goto QNaN_Operand;
+         if (EXTRACTED64(*frB, 12, 12) == 0
+             && EXTRACTED64(*frB, 13, 63) > 0) goto SNaN_Operand;
+       }
+       /* handle them */
+       Disabled_Exponent_Underflow:
+         sign = EXTRACTED64(*frB, 0, 0);
+         if (EXTRACTED64(*frB, 1, 11) == 0) {
+           exp = -1022;
+           frac_grx = INSERTED64(EXTRACTED64(*frB, 12, 63), 1, 52);
+         }
+         if (EXTRACTED64(*frB, 1, 11) > 0) {
+           exp = EXTRACTED64(*frB, 1, 11) - 1023;
+           frac_grx = BIT64(0) | INSERTED64(EXTRACTED64(*frB, 12, 63), 1, 52);
+         }
+         Denormalize_Operand:
+           /* G|R|X == zero from above */
+           while (exp < -126) {
+             exp = exp - 1;
+             frac_grx = (INSERTED64(EXTRACTED64(frac_grx, 0, 54), 1, 55)
+                         | MASKED64(frac_grx, 55, 55));
+           }
+         FPSCR_SET_UX(EXTRACTED64(frac_grx, 24, 55) > 0);
+         Round_Single(processor, sign, &exp, &frac_grx);
+         FPSCR_SET_XX(FPSCR & fpscr_fi);
+         if (EXTRACTED64(frac_grx, 0, 52) == 0) {
+           *frT = INSERTED64(sign, 0, 0);
+           if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_zero);
+           if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_neg_zero);
+         }
+         if (EXTRACTED64(frac_grx, 0, 52) > 0) {
+           if (EXTRACTED64(frac_grx, 0, 0) == 1) {
+             if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
+             if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_neg_normal_number);
+           }
+           if (EXTRACTED64(frac_grx, 0, 0) == 0) {
+             if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_denormalized_number);
+             if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_neg_denormalized_number);
+           }
+           /*Normalize_Operand:*/
+             while (EXTRACTED64(frac_grx, 0, 0) == 0) {
+               exp = exp - 1;
+               frac_grx = INSERTED64(EXTRACTED64(frac_grx, 1,  52), 0, 51);
+             }
+           *frT = (INSERTED64(sign, 0, 0)
+                   | INSERTED64(exp + 1023, 1, 11)
+                   | INSERTED64(EXTRACTED64(frac_grx, 1, 52), 12, 63));
+         }
+         goto Done;
+       Enabled_Exponent_Underflow:
+         FPSCR_SET_UX(1);
+         sign = EXTRACTED64(*frB, 0, 0);
+         if (EXTRACTED64(*frB, 1, 11) == 0) {
+           exp = -1022;
+           frac_grx = INSERTED64(EXTRACTED64(*frB, 12, 63), 1, 52);
+         }
+         if (EXTRACTED64(*frB, 1, 11) > 0) {
+           exp = EXTRACTED64(*frB, 1, 11) - 1023;
+           frac_grx = (BIT64(0) |
+                       INSERTED64(EXTRACTED64(*frB, 12, 63), 1, 52));
+         }
+         /*Normalize_Operand:*/
+           while (EXTRACTED64(frac_grx, 0, 0) == 0) {
+             exp = exp - 1;
+             frac_grx = INSERTED64(EXTRACTED64(frac_grx, 1, 52), 0, 51);
+           }
+         Round_Single(processor, sign, &exp, &frac_grx);
+         FPSCR_SET_XX(FPSCR & fpscr_fi);
+         exp = exp + 192;
+         *frT = (INSERTED64(sign, 0, 0)
+                 | INSERTED64(exp + 1023, 1, 11)
+                 | INSERTED64(EXTRACTED64(frac_grx, 1, 52), 12, 63));
+         if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
+         if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_neg_normal_number);
+         goto Done;
+       Disabled_Exponent_Overflow:
+         FPSCR_SET_OX(1);
+         if ((FPSCR & fpscr_rn) == fpscr_rn_round_to_nearest) {
+           if (EXTRACTED64(*frB, 0, 0) == 0) {
+             *frT = INSERTED64(0x7FF00000, 0, 31) | 0x00000000;
+             FPSCR_SET_FPRF(fpscr_rf_pos_infinity);
+           }
+           if (EXTRACTED64(*frB, 0, 0) == 1) {
+             *frT = INSERTED64(0xFFF00000, 0, 31) | 0x00000000;
+             FPSCR_SET_FPRF(fpscr_rf_neg_infinity);
+           }
+         }
+         if ((FPSCR & fpscr_rn) == fpscr_rn_round_towards_zero) {
+           if (EXTRACTED64(*frB, 0, 0) == 0) {
+             *frT = INSERTED64(0x47EFFFFF, 0, 31) | 0xE0000000;
+             FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
+           }
+           if (EXTRACTED64(*frB, 0, 0) == 1) {
+             *frT = INSERTED64(0xC7EFFFFF, 0, 31) | 0xE0000000;
+             FPSCR_SET_FPRF(fpscr_rf_neg_normal_number);
+           }
+         }
+         if ((FPSCR & fpscr_rn) == fpscr_rn_round_towards_pos_infinity) {
+           if (EXTRACTED64(*frB, 0, 0) == 0) {
+             *frT = INSERTED64(0x7FF00000, 0, 31) | 0x00000000;
+             FPSCR_SET_FPRF(fpscr_rf_pos_infinity);
+           }
+           if (EXTRACTED64(*frB, 0, 0) == 1) {
+             *frT = INSERTED64(0xC7EFFFFF, 0, 31) | 0xE0000000;
+             FPSCR_SET_FPRF(fpscr_rf_neg_normal_number);
+           }
+         }
+         if ((FPSCR & fpscr_rn) == fpscr_rn_round_towards_neg_infinity) {
+           if (EXTRACTED64(*frB, 0, 0) == 0) {
+             *frT = INSERTED64(0x47EFFFFF, 0, 31) | 0xE0000000;
+             FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
+           }
+           if (EXTRACTED64(*frB, 0, 0) == 1) {
+             *frT = INSERTED64(0xFFF00000, 0, 31) | 0x00000000;
+             FPSCR_SET_FPRF(fpscr_rf_neg_infinity);
+           }
+         }
+         /* FPSCR[FR] <- undefined */
+         FPSCR_SET_FI(1);
+         FPSCR_SET_XX(1);
+         goto Done;
+       Enabled_Exponent_Overflow:
+         sign = EXTRACTED64(*frB, 0, 0);
+         exp = EXTRACTED64(*frB, 1, 11) - 1023;
+         frac_grx = BIT64(0) | INSERTED64(EXTRACTED64(*frB, 12, 63), 1, 52);
+         Round_Single(processor, sign, &exp, &frac_grx);
+         FPSCR_SET_XX(FPSCR & fpscr_fi);
+         Enabled_Overflow:
+           FPSCR_SET_OX(1);
+           exp = exp - 192;
+           *frT = (INSERTED64(sign, 0, 0)
+                   | INSERTED64(exp + 1023, 1, 11)
+                   | INSERTED64(EXTRACTED64(frac_grx, 1, 52), 12, 63));
+           if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
+           if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_neg_normal_number);
+         goto Done;
+       Zero_Operand:
+         *frT = *frB;
+         if (EXTRACTED64(*frB, 0, 0) == 0) FPSCR_SET_FPRF(fpscr_rf_pos_zero);
+         if (EXTRACTED64(*frB, 0, 0) == 1) FPSCR_SET_FPRF(fpscr_rf_neg_zero);
+         FPSCR_SET_FR(0);
+         FPSCR_SET_FI(0);
+         goto Done;
+       Infinity_Operand:
+         *frT = *frB;
+         if (EXTRACTED64(*frB, 0, 0) == 0) FPSCR_SET_FPRF(fpscr_rf_pos_infinity);
+         if (EXTRACTED64(*frB, 0, 0) == 1) FPSCR_SET_FPRF(fpscr_rf_neg_infinity);
+         FPSCR_SET_FR(0);
+         FPSCR_SET_FI(0);
+         goto Done;
+       QNaN_Operand:
+         *frT = INSERTED64(EXTRACTED64(*frB, 0, 34), 0, 34);
+         FPSCR_SET_FPRF(fpscr_rf_quiet_nan);
+         FPSCR_SET_FR(0);
+         FPSCR_SET_FI(0);
+         goto Done;
+       SNaN_Operand:
+         FPSCR_OR_VX(fpscr_vxsnan);
+         if ((FPSCR & fpscr_ve) == 0) {
+           *frT = (MASKED64(*frB, 0, 11)
+                   | BIT64(12)
+                   | MASKED64(*frB, 13, 34));
+           FPSCR_SET_FPRF(fpscr_rf_quiet_nan);
+         }
+         FPSCR_SET_FR(0);
+         FPSCR_SET_FI(0);
+         goto Done;
+       Normal_Operand:
+         sign = EXTRACTED64(*frB, 0, 0);
+         exp = EXTRACTED64(*frB, 1, 11) - 1023;
+         frac_grx = BIT64(0) | INSERTED64(EXTRACTED64(*frB, 12, 63), 1, 52);
+         Round_Single(processor, sign, &exp, &frac_grx);
+         FPSCR_SET_XX(FPSCR & fpscr_fi);
+         if (exp > 127 && (FPSCR & fpscr_oe) == 0) goto Disabled_Exponent_Overflow;
+         if (exp > 127 && (FPSCR & fpscr_oe) != 0) goto Enabled_Overflow;
+         *frT = (INSERTED64(sign, 0, 0)
+                 | INSERTED64(exp + 1023, 1, 11)
+                 | INSERTED64(EXTRACTED64(frac_grx, 1, 52), 12, 63));
+         if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
+         if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_neg_normal_number);
+         goto Done;
+       Done:
+0.63,6.FRT,11./,16.FRB,21.814,31.Rc:X:64,f::Floating Convert To Integer Doubleword
+0.63,6.FRT,11./,16.FRB,21.815,31.Rc:X:64,f::Floating Convert To Integer Doubleword with round towards Zero
+0.63,6.FRT,11./,16.FRB,21.14,31.Rc:X:f::Floating Convert To Integer Word
+0.63,6.FRT,11./,16.FRB,21.15,31.Rc:X:f:fctiwz:Floating Convert To Integer Word with round towards Zero
+       FPSCR_BEGIN;
+       convert_to_integer(processor, cia,
+                          frT, *frB,
+                          fpscr_rn_round_towards_zero, 32);
+       FPSCR_END(Rc);
+0.63,6.FRT,11./,16.FRB,21.846,31.Rc:X:64,f::Floating Convert from Integer Doubleword
+       int sign = EXTRACTED64(*frB, 0, 0);
+       int exp = 63;
+       unsigned64 frac = *frB;
+       if (frac == 0) goto Zero_Operand;
+       if (sign == 1) frac = ~frac + 1;
+       while (EXTRACTED64(frac, 0, 0) == 0) {
+         /*??? do the loop 0 times if (FRB) = max negative integer */
+         frac = INSERTED64(EXTRACTED64(frac, 1, 63), 0, 62);
+         exp = exp - 1;
+       }
+       Round_Float(processor, sign, &exp, &frac, FPSCR & fpscr_rn);
+       if (sign == 0) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
+       if (sign == 1) FPSCR_SET_FPRF(fpscr_rf_pos_normal_number);
+       *frT = (INSERTED64(sign, 0, 0)
+               | INSERTED64(exp + 1023, 1, 11)
+               | INSERTED64(EXTRACTED64(frac, 1, 52), 12, 63));
+       goto Done;
+       /**/
+       Zero_Operand:
+         FPSCR_SET_FR(0);
+         FPSCR_SET_FI(0);
+         FPSCR_SET_FPRF(fpscr_rf_pos_zero);
+         *frT = 0;
+         goto Done;
+       /**/
+       Done:
+
+#
+# I.4.6.7 Floating-Point Compare Instructions
+#
+
+0.63,6.BF,9./,11.FRA,16.FRB,21.0,31./:X:f:fcmpu:Floating Compare Unordered
+       FPSCR_BEGIN;
+       unsigned c;
+       if (is_NaN(*frA, 0) || is_NaN(*frB, 0))
+         c = cr_i_summary_overflow; /* 0b0001 - (FRA) ? (FRB) */
+       else if (is_less_than(frA, frB))
+         c = cr_i_negative; /* 0b1000 - (FRA) < (FRB) */
+       else if (is_greater_than(frA, frB))
+         c = cr_i_positive; /* 0b0100 - (FRA) > (FRB) */
+       else
+         c = cr_i_zero; /* 0b0010 - (FRA) = (FRB) */
+       FPSCR_SET_FPCC(c);
+       CR_SET(BF, c); /* CR[4*BF..4*BF+3] = c */
+       if (is_SNaN(*frA, 0) || is_SNaN(*frB, 0))
+         FPSCR_OR_VX(fpscr_vxsnan);
+       FPSCR_END(0);
+0.63,6.BF,9./,11.FRA,16.FRB,21.32,31./:X:f:fcmpo:Floating Compare Ordered
+       FPSCR_BEGIN;
+       unsigned c;
+       if (is_NaN(*frA, 0) || is_NaN(*frB, 0))
+         c = cr_i_summary_overflow; /* 0b0001 - (FRA) ? (FRB) */
+       else if (is_less_than(frA, frB))
+         c = cr_i_negative; /* 0b1000 - (FRA) < (FRB) */
+       else if (is_greater_than(frA, frB))
+         c = cr_i_positive; /* 0b0100 - (FRA) > (FRB) */
+       else
+         c = cr_i_zero; /* 0b0010 - (FRA) = (FRB) */
+       FPSCR_SET_FPCC(c);
+       CR_SET(BF, c); /* CR[4*BF..4*BF+3] = c */
+       if (is_SNaN(*frA, 0) || is_SNaN(*frB, 0)) {
+         FPSCR_OR_VX(fpscr_vxsnan);
+         if ((FPSCR & fpscr_ve) == 0)
+           FPSCR_OR_VX(fpscr_vxvc);
+       }
+       else if (is_QNaN(*frA, 0) || is_QNaN(*frB, 0)) {
+         FPSCR_OR_VX(fpscr_vxvc);
+       }
+       FPSCR_END(0);
+
+
+#
+# I.4.6.8 Floating-Point Status and Control Register Instructions
+#
+
+0.63,6.FRT,11./,16./,21.583,31.Rc:X:f::Move From FPSCR
+0.63,6.BF,9./,11.BFA,14./,16./,21.64,31./:X:f::Move to Condition Register from FPSCR
+0.64,6.BF,9./,11./,16.U,20./,21.134,31.Rc:X:f::Move To FPSCR Field Immediate
+0.63,6./,7.FLM,15./,16.FRB,21.711,31.Rc:XFL:f::Move To FPSCR Fields
+0.63,6.BT,11./,16./,21.70,31.Rc:X:f::Move To FPSCR Bit 0
+0.63,6.BT,11./,16./,21.38,31.Rc:X:f::Move To FPSCR Bit 1
+
+
+#
+# I.A.1.1 Floating-Point Store Instruction
+#
+0.31,6.FRS,11.RA,16.RB,21.983,31./:X:f::Store Floating-Point as Integer Word Indexed
+
+#
+# I.A.1.2 Floating-Point Arithmetic Instructions
+#
+
+0.63,6.FRT,11./,16.FRB,21./,26.22,31.Rc:A:f::Floating Square Root
+0.59,6.FRT,11./,16.FRB,21./,26.22,31.Rc:A:f::Floating Square Root Single
+
+0.59,6.FRT,11./,16.FRB,21./,26.24,31.Rc:A:f::Floating Reciprocal Estimate Single
+0.63,6.FRT,11./,16.FRB,21./,26.26,31.Rc:A:f::Floating Reciprocal Square Root Estimate
+
+#
+# I.A.1.3 Floating-Point Select Instruction
+#
+
+0.63,6.FRT,11.FRA,16.FRB,21.FRC,26.23,31.Rc:A:f::Floating Select
+
+
+#
+# II.3.2 Cache Management Instructions
+#
+
+0.31,6./,11.RA,16.RB,21.982,31./:X::icbi:Instruction Cache Block Invalidate
+       ;       /* nop for now */
+
+0.19,6./,11./,16./,21.150,31./:XL::isync:Instruction Synchronize
+       cpu_synchronize_context(processor);
+
+
+#
+# II.3.2.2 Data Cache Instructions
+#
+
+0.31,6./,11.RA,16.RB,21.278,31./:X:::Data Cache Block Touch
+0.31,6./,11.RA,16.RB,21.246,31./:X:::Data Cache Block Touch for Store
+0.31,6./,11.RA,16.RB,21.1014,31./:X:::Data Cache Block set to Zero
+0.31,6./,11.RA,16.RB,21.54,31./:X:::Data Cache Block Store
+0.31,6./,11.RA,16.RB,21.86,31./:X:::Data Cache Block Flush
+
+#
+# II.3.3 Envorce In-order Execution of I/O Instruction
+#
+
+0.31,6./,11./,16./,21.854,31./:X::eieio:Enforce In-order Execution of I/O
+       /* Since this model has no instruction overlap
+          this instruction need do nothing */
+
+#
+# II.4.1 Time Base Instructions
+#
+
+0.31,6.RT,11.tbr,21.371,31./:XFX::mftb:Move From Time Base
+       int n = (tbr{5:9} << 5) | tbr{0:4};
+       if (n == 268) {
+         if (is_64bit_implementation) *rT = TB;
+         else                         *rT = EXTRACTED64(TB, 32, 63);
+       }
+       else if (n == 269) {
+         if (is_64bit_implementation) *rT = EXTRACTED64(TB, 0, 31);
+         else                         *rT = EXTRACTED64(TB, 0, 31);
+       }
+       else
+         program_interrupt(processor, cia,
+                           illegal_instruction_program_interrupt);
+
+
+#
+# III.2.3.1 System Linkage Instructions
+#
+
+#0.17,6./,11./,16./,30.1,31./:SC:::System Call
+0.19,6./,11./,16./,21.50,31./:XL:::Return From Interrupt
+
+#
+# III.3.4.1 Move to/from System Register Instructions
+#
+
+#0.31,6.RS,11.spr,21.467,31./:XFX:::Move To Special Purpose Register
+#0.31,6.RT,11.spr,21.339,31./:XFX:::Move From Special Purpose Register
+0.31,6.RS,11./,16./,21.146,31./:X:::Move To Machine State Register
+       if (IS_PROBLEM_STATE(processor))
+         program_interrupt(processor, cia,
+                           privileged_instruction_program_interrupt);
+       else
+         MSR = *rS;
+0.31,6.RT,11./,16./,21.83,31./:X:::Move From Machine State Register
+       if (IS_PROBLEM_STATE(processor))
+         program_interrupt(processor, cia,
+                           privileged_instruction_program_interrupt);
+       else
+         *rT = MSR;
+
+
+#
+# III.4.11.1 Cache Management Instructions
+#
+
+0.31,6./,11.RA,16.RB,21.470,31./:X::dcbi:Data Cache Block Invalidate
+       ;       /* nop for now */
+
+#
+# III.4.11.2 Segment Register Manipulation Instructions
+#
+
+0.31,6.RS,11./,12.SR,16./,21.210,31./:X:32:mtsr %SR,%RS:Move To Segment Register
+       if (IS_PROBLEM_STATE(processor))
+         program_interrupt(processor, cia,
+                           privileged_instruction_program_interrupt);
+       else
+         SEGREG(SR) = *rS;
+0.31,6.RS,11./,16.RB,21.242,31./:X:32:mtsrin %RS,%RB:Move To Segment Register Indirect
+       if (IS_PROBLEM_STATE(processor))
+         program_interrupt(processor, cia,
+                           privileged_instruction_program_interrupt);
+       else
+         SEGREG(EXTRACTED32(*rB, 0, 3)) = *rS;
+0.31,6.RT,11./,12.SR,16./,21.595,31./:X:32:mfsr %RT,%RS:Move From Segment Register
+       if (IS_PROBLEM_STATE(processor))
+         program_interrupt(processor, cia,
+                           privileged_instruction_program_interrupt);
+       else
+         *rT = SEGREG(SR);
+0.31,6.RT,11./,16.RB,21.659,31./:X:32:mfsrin %RT,%RB:Move From Segment Register Indirect
+       if (IS_PROBLEM_STATE(processor))
+         program_interrupt(processor, cia,
+                           privileged_instruction_program_interrupt);
+       else
+         *rT = SEGREG(EXTRACTED32(*rB, 0, 3));
+
+
+#
+# III.4.11.3 Lookaside Buffer Management Instructions (Optional)
+#
+
+0.31,6./,11./,16.RB,21.434,31./:X:64::SLB Invalidate Entry
+0.31,6./,11./,16./,21.498,31./:X:64::SLB Invalidate All
+
+0.31,6./,11./,16.RB,21.306,31./:X:::TLB Invalidate Entry
+0.31,6./,11./,16./,21.370,31./:X:::TLB Invalidate All
+
+0.31,6./,11./,16./,21.566,31./:X:::TLB Sychronize
+
+
+#
+# III.A.1.2 External Access Instructions
+#
+
+0.31,6.RT,11.RA,16.RB,21.310,31./:X:earwax::External Control In Word Indexed
+0.31,6.RS,11.RA,16.RB,21.438,31./:X:earwax::External Control Out Word Indexed