bits.h
build-psim
config.in
+config.make
+config.hdr
configure
configure.in
core.c
emul_netbsd.h
events.c
events.h
+filter_filename.c
+filter_filename.h
idecode_branch.h
idecode_expression.h
idecode_fields.h
+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,
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!
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.
* 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
* 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
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
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
* 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.
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.
* 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.
({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,
* 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.
* 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
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
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.
* 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.
* 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)
* 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).
* 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
* 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.
HDEFINES = @HDEFINES@
TDEFINES =
+IGEN_FLAGS = $(IGEN_DUPLICATE) $(IGEN_FILTER)
.NOEXPORT:
MAKEOVERRIDES=
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) $<
words.h \
ppc-endian.h \
debug.h \
+ filter_filename.h \
bits.h \
sim_callbacks.h
# first
LIB_OBJ = \
debug.o \
+ filter_filename.o \
bits.o \
ppc-endian.o \
os_emul.o \
# 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
# 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
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
--- /dev/null
+#! /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
--- /dev/null
+#! /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
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";;
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
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";;
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
--- /dev/null
+/* 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_ */
--- /dev/null
+/* 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_ */
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
--- /dev/null
+#
+# 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