From c143ef6296268bb98a697572a589d47bb375d372 Mon Sep 17 00:00:00 2001 From: Michael Meissner Date: Wed, 1 Nov 1995 19:32:38 +0000 Subject: [PATCH] Lots of changes --- sim/ppc/.Sanitize | 4 + sim/ppc/ChangeLog | 106 +- sim/ppc/Makefile.in | 39 +- sim/ppc/config.hdr | 52 + sim/ppc/config.make | 53 + sim/ppc/configure | 173 +-- sim/ppc/configure.in | 173 +-- sim/ppc/debug.h | 118 ++ sim/ppc/emul_netbsd.c | 1202 ++++++++++++++++ sim/ppc/filter_filename.c | 36 + sim/ppc/filter_filename.h | 27 + sim/ppc/igen.c | 2834 +++++++++++++++++++++++++++++++++++++ sim/ppc/misc.h | 48 + sim/ppc/ppc-instructions | 2414 +++++++++++++++++++++++++++++++ 14 files changed, 7066 insertions(+), 213 deletions(-) create mode 100755 sim/ppc/config.hdr create mode 100755 sim/ppc/config.make create mode 100644 sim/ppc/debug.h create mode 100644 sim/ppc/emul_netbsd.c create mode 100644 sim/ppc/filter_filename.c create mode 100644 sim/ppc/filter_filename.h create mode 100644 sim/ppc/igen.c create mode 100644 sim/ppc/misc.h create mode 100644 sim/ppc/ppc-instructions diff --git a/sim/ppc/.Sanitize b/sim/ppc/.Sanitize index efa34bda1d..195a020332 100644 --- a/sim/ppc/.Sanitize +++ b/sim/ppc/.Sanitize @@ -33,6 +33,8 @@ bits.c bits.h build-psim config.in +config.make +config.hdr configure configure.in core.c @@ -55,6 +57,8 @@ emul_netbsd.c emul_netbsd.h events.c events.h +filter_filename.c +filter_filename.h idecode_branch.h idecode_expression.h idecode_fields.h diff --git a/sim/ppc/ChangeLog b/sim/ppc/ChangeLog index feaef07326..66b2465c9c 100644 --- a/sim/ppc/ChangeLog +++ b/sim/ppc/ChangeLog @@ -1,3 +1,53 @@ +Wed Nov 1 10:49:48 1995 Michael Meissner + + * 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 * configure.in: Add support for --enable-sim-inline, @@ -6,19 +56,19 @@ Tue Oct 31 15:20:04 1995 Michael Meissner 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 +Fri Oct 27 19:26:27 1995 Andrew Cagney * 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 +Thu Oct 26 18:31:58 1995 Andrew Cagney * ppc-endian.c (SWAP_8): Fix 8 byte swap! @@ -30,18 +80,18 @@ Thu Oct 26 18:31:58 1995 Andrew Cagney trace_semantics is now different to trace_idecode, the former checks the cache. -Tue Oct 24 21:54:13 1995 Andrew Cagney +Tue Oct 24 21:54:13 1995 Andrew Cagney * ppc-instructions (mtsrin): Missing instruction * ppc-instructions (mfsrin): Missing instruction * ppc-instructions (eieio): Missing instruction -Tue Oct 24 20:55:29 1995 Andrew Cagney +Tue Oct 24 20:55:29 1995 Andrew Cagney * 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 +Mon Oct 23 23:48:59 1995 Andrew Cagney * std-config.h (SEMANTICS_INLINE): Tidy up notes on each of the INLINE macros. Make SEMANTICS_INLINE == 1 if DEFAULT_INLINE == 2. @@ -55,7 +105,7 @@ Mon Oct 23 23:48:59 1995 Andrew Cagney * 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 +Mon Oct 23 00:31:50 1995 Andrew Cagney * os_emul.[hc], emul_generic.[hc], emul_netbsd.[hc]: replace system.[hc]. Start of suport for multiple emulations and @@ -64,7 +114,7 @@ Mon Oct 23 00:31:50 1995 Andrew Cagney * emul_generic.[hc]: Start of code to implement proper system call tracing (from spy). -Sun Oct 22 21:33:51 1995 Andrew Cagney +Sun Oct 22 21:33:51 1995 Andrew Cagney * cpu.h, cpu.c (cpu_init): New function, zero the registers before the processor is started. Fixes problem of registers being @@ -84,7 +134,7 @@ Sun Oct 22 21:33:51 1995 Andrew Cagney performing an isync when the instruction stream doesn't contain one. -Sun Oct 22 19:27:48 1995 Andrew Cagney +Sun Oct 22 19:27:48 1995 Andrew Cagney * mon.h (new), mon.c (new), std-config.h (WITH_MON): Performance monitoring module. Counts both instructions issued and @@ -104,20 +154,20 @@ Sun Oct 22 19:27:48 1995 Andrew Cagney 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 +Sun Oct 22 18:42:45 1995 Andrew Cagney * 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 +Fri Oct 20 17:26:54 1995 Andrew Cagney * 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 +Wed Oct 18 23:02:20 1995 Andrew Cagney * Makefile.in, gen.c(delete), igen.c(new), dgen.c(new), lf.[ch](new), table.[ch](new): Split into two generators - igen @@ -161,7 +211,7 @@ Wed Oct 18 23:02:20 1995 Andrew Cagney * ppc-instructions (64bit Floating Convert from Integer Doubleword): Correct call to Round_Float(). -Mon Oct 16 00:31:20 1995 Andrew Cagney +Mon Oct 16 00:31:20 1995 Andrew Cagney * basics.h: #include "sim_callbacks.h" earlier so that its prototypes are declared in all other header files. @@ -177,7 +227,7 @@ Mon Oct 16 00:31:20 1995 Andrew Cagney 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 +Sun Oct 15 22:16:11 1995 Andrew Cagney * devices.h, devices.c, debug.h, debug.c: add macro's for tracing of each device. Make parameter names consistent so macros work. @@ -191,7 +241,7 @@ Sun Oct 15 22:16:11 1995 Andrew Cagney * 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 +Sun Oct 15 20:33:20 1995 Andrew Cagney * debug.h, debug.c (trace_option): New function. Parses the trace option, updating the trace array. @@ -301,7 +351,7 @@ Thu Oct 12 11:35:53 1995 Michael Meissner ({CORE,VM,CPU,EVENTS,REGISTERS,INTERRUPTS}_INLINE): Ditto. ({SPREG,IDECODE}_INLINE): Ditto. -Wed Oct 11 17:13:15 1995 Andrew Cagney +Wed Oct 11 17:13:15 1995 Andrew Cagney * ppc-instructions: Initial cut of floating point suport added. Of note include - use of host IEEE floating point instructions, @@ -318,7 +368,7 @@ Wed Oct 11 17:13:15 1995 Andrew Cagney * Makefile.in et.al (sorry): tweek to use new core, core_map and core.h. -Wed Oct 11 12:10:26 1995 Andrew Cagney +Wed Oct 11 12:10:26 1995 Andrew Cagney * sim_calls.c, main.c: Add -g (trace_gdb) option, add tracing to most of the other functions in sim_calls.c. @@ -329,7 +379,7 @@ Wed Oct 11 12:10:26 1995 Andrew Cagney * vm.c, vm_n.h, Makefile.in: ditto -Tue Oct 10 15:42:59 1995 Andrew Cagney +Tue Oct 10 15:42:59 1995 Andrew Cagney * devices.h, devices.c, memory_map.h, memory_map.c: Changed callback interface so that there is a read/write buffer but no @@ -341,12 +391,12 @@ Tue Oct 10 15:42:59 1995 Andrew Cagney eliminate transfer_mode (raw or cooked) parameter from read/write buffer. -Fri Oct 6 20:23:56 1995 Andrew Cagney +Fri Oct 6 20:23:56 1995 Andrew Cagney * ppc-instructions (fmul, fmuls): correct instruction format - had FRB instead of FRC. -Wed Oct 4 17:31:12 1995 Andrew Cagney +Wed Oct 4 17:31:12 1995 Andrew Cagney * psim.c, device_tree.h, device_tree.c, devices.c (printd_*, scand_*): new functions to parse/print fields in device names @@ -360,7 +410,7 @@ Wed Oct 4 17:31:12 1995 Andrew Cagney variable number of arguments. This gives greater flexability and greater chance of bugs. -Tue Oct 3 22:01:56 1995 Andrew Cagney +Tue Oct 3 22:01:56 1995 Andrew Cagney * main.c (printf_filtered, error): Missing va_end() to close off variable argument use. @@ -483,7 +533,7 @@ Fri Sep 8 09:51:03 1995 Michael Meissner * basics.h (sysdep.h): Don't include it. * Makefile.in (BASICS_H): Remove sysdep.h. -Wed Sep 6 13:25:42 1995 Andrew Cagney +Wed Sep 6 13:25:42 1995 Andrew Cagney * core.c (core_add_data): First growth of bss was being put at wrong address (0) instead of &end. @@ -491,7 +541,7 @@ Wed Sep 6 13:25:42 1995 Andrew Cagney * 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 +Wed Sep 6 00:46:10 1995 Andrew Cagney * system.c (system_call): Fix SYS_break - was aligning bss to a page boundary instead of just an 8 byte one; On first call sbrk(0) @@ -537,7 +587,7 @@ Tue Aug 22 09:31:18 1995 Michael Meissner * configure.in: Clone from other simulator targets. * configure: Generate via autoconf from configure.in. -Sat Aug 19 09:05:32 1995 Andrew Cagney +Sat Aug 19 09:05:32 1995 Andrew Cagney * ppc-instructions: fix srawi (was geting XER[CA] real wrong). @@ -548,14 +598,14 @@ Sat Aug 19 09:05:32 1995 Andrew Cagney * main.c (main): really stupid. Wasn't exiting with correct status -Fri Aug 18 00:38:01 1995 Andrew Cagney +Fri Aug 18 00:38:01 1995 Andrew Cagney * 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 +Thu Aug 17 14:29:18 1995 Andrew Cagney * device_tree.c (create_option_device_node): Alignment rules (at least for the moment) now are for strict alignment only for LE OEA @@ -563,7 +613,7 @@ Thu Aug 17 14:29:18 1995 Andrew Cagney * system.c (system_call) SYS_exit: Wasn't exiting with correct status. -Thu Aug 17 01:16:38 1995 Andrew Cagney +Thu Aug 17 01:16:38 1995 Andrew Cagney * vm.c (DEFINE_VM_DATA_MAP_WRITE_N): For miss aligned transfer forgot to return. diff --git a/sim/ppc/Makefile.in b/sim/ppc/Makefile.in index d92ca568de..f2c7625c7c 100644 --- a/sim/ppc/Makefile.in +++ b/sim/ppc/Makefile.in @@ -68,6 +68,7 @@ RANLIB = @RANLIB@ HDEFINES = @HDEFINES@ TDEFINES = +IGEN_FLAGS = $(IGEN_DUPLICATE) $(IGEN_FILTER) .NOEXPORT: MAKEOVERRIDES= @@ -77,24 +78,15 @@ BFD_INCLUDES = -I../../bfd -I$(srcdir)/../../bfd GDB_INCLUDES = -I../../gdb -I$(srcdir)/../../gdb -I$(srcdir)/../../gdb/config -I$(srcdir)/../../mmalloc INCLUDES = -I. -I$(srcdir) $(LIB_INCLUDES) $(BFD_INCLUDES) $(GDB_INCLUDES) -CONFIG_FILE = std-config.h - -# See inline.h for appropriate flags to set -INLINE_CFLAGS = # -g0 -DDEFAULT_INLINE=2 -IGEN_FLAGS = -f 64 # -f 64 -e -IGEN_OPCODE_RULES = ppc-opcode-simple # ppc-opcode-complex -DGEN_FLAGS = # # -s - - LIBIBERTY_LIB = ../../libiberty/libiberty.a BFD_LIB = ../../bfd/libbfd.a -TARGETLIB = libsim.a +TARGETLIB = libsim.a all: run $(TARGETLIB) $(GDB_OBJ) .c.o: - $(CC) -c $(CFLAGS) $(INLINE_CFLAGS) $(HDEFINES) $(TDEFINES) $(INCLUDES) $< + $(CC) -c $(CFLAGS) $(INLINE_CFLAGS) $(SIM_CFLAGS) $(HDEFINES) $(TDEFINES) $(INCLUDES) $< @@ -104,6 +96,7 @@ BASICS_H = \ words.h \ ppc-endian.h \ debug.h \ + filter_filename.h \ bits.h \ sim_callbacks.h @@ -183,6 +176,7 @@ MAIN_SRC = \ # first LIB_OBJ = \ debug.o \ + filter_filename.o \ bits.o \ ppc-endian.o \ os_emul.o \ @@ -221,11 +215,12 @@ $(TARGETLIB): tmp-igen tmp-dgen $(LIB_OBJ) $(GDB_OBJ) # Given that inlines are turned on now, rebuild psim whenever # anything changes. -psim.o: psim.c psim.h $(CPU_H) $(IDECODE_H) $(INLINE) $(LIB_SRC) +psim.o: psim.c psim.h $(CPU_H) $(IDECODE_H) $(INLINE) $(LIB_SRC) $(BUILT_SRC) bits.o: bits.c $(BASICS_H) debug.o: debug.c $(BASICS_H) +filter_filename.o: filter_filename.c $(BASICS_H) ppc-endian.o: ppc-endian.c ppc-endian.h \ config.h ppc-config.h words.h sim_callbacks.h @@ -314,16 +309,16 @@ tmp-igen: igen ppc-instructions $(IGEN_OPCODE_RULES) ppc-cache-rules $(srcdir)/. # itable.h itable.c icache.h idecode.h idecode.c semantics.h semantics.c: tmp-igen # spreg.h spreg.c: tmp-dgen -dgen: dgen.o table.o lf.o misc.o - $(CC_FOR_BUILD) $(CFLAGS) $(LDFLAGS) -o dgen dgen.o table.o lf.o misc.o $(LIBIBERTY_LIB) $(LIBS) +dgen: dgen.o table.o lf.o misc.o filter_filename.o + $(CC_FOR_BUILD) $(CFLAGS) $(LDFLAGS) -o dgen dgen.o table.o lf.o misc.o filter_filename.o $(LIBIBERTY_LIB) $(LIBS) -igen: igen.o table.o lf.o misc.o - $(CC_FOR_BUILD) $(CFLAGS) $(LDFLAGS) -o igen igen.o table.o lf.o misc.o $(LIBIBERTY_LIB) $(LIBS) +igen: igen.o table.o lf.o misc.o filter_filename.o + $(CC_FOR_BUILD) $(CFLAGS) $(LDFLAGS) -o igen igen.o table.o lf.o misc.o filter_filename.o $(LIBIBERTY_LIB) $(LIBS) -table.o: misc.h lf.h table.h -lf.o: misc.h lf.h -dgen.o igen.o: misc.h lf.h table.h -misc.o: misc.h +table.o: misc.h filter_filename.h lf.h table.h +lf.o: misc.h filter_filename.h lf.h +dgen.o igen.o: misc.h filter_filename.h lf.h table.h +misc.o: misc.h filter_filename.h # With out this #, make thinks that misc.o doesn't have a rule tags etags: TAGS @@ -344,9 +339,11 @@ config.h: stamp-h ; @true stamp-h: config.in config.status CONFIG_FILES= CONFIG_HEADERS=config.h:config.in $(SHELL) ./config.status -config.status: configure +config.status: configure config.make config.hdr $(SHELL) ./config.status --recheck install: $(INSTALL_XFORM) run $(bindir)/run + +# Make variables generated automatically by configure follow this diff --git a/sim/ppc/config.hdr b/sim/ppc/config.hdr new file mode 100755 index 0000000000..98fa86b1f1 --- /dev/null +++ b/sim/ppc/config.hdr @@ -0,0 +1,52 @@ +#! /bin/sh + +# Helper script to turn --enable-sim-xxx switches into defines + +# Arg 1 -- header name +# Arg 2 -- define name +# Arg 3 -- --enable-sim switch spelling +# Arg 4 -- --enable-sim switch value +# the remaining switches are paired, with the first being the value to test arg 4 against +# and the second is the value to put in the define if it matches + +hdr="$1" +shift + +define="$1" +shift + +switch="$1" +shift + +value="$1" +shift + +while test $# -gt 1; do + test_value="$1" + shift + + set_value="$1" + shift + + if test x"$value" = x"$test_value" -o x"$test_value" = x"*"; then + echo "Defining $define=$set_value" + (echo "" + if test x"$value" = x""; then + echo "/* no $switch */" + elif test x"$value" = x"yes"; then + echo "/* $switch */" + else + echo "/* $switch=$value */" + fi + + echo "#ifndef $define" + echo "#define $define $set_value" + echo "#endif") >> $hdr + exit 0; + fi +done + +if test x"$value" != x"" -a x"$value" != x"no"; then + echo "$switch=$value is not supported" 1>&2 + exit 1 +fi diff --git a/sim/ppc/config.make b/sim/ppc/config.make new file mode 100755 index 0000000000..388fe36047 --- /dev/null +++ b/sim/ppc/config.make @@ -0,0 +1,53 @@ +#! /bin/sh + +# Helper script to turn --enable-sim-xxx switches into make variables + +# Arg 1 -- header name +# Arg 2 -- define name +# Arg 3 -- --enable-sim switch spelling +# Arg 4 -- --enable-sim switch value +# the remaining switches are paired, with the first being the value to test arg 4 against +# and the second is the value to put in the define if it matches + +make="$1" +shift + +makevar="$1" +shift + +switch="$1" +shift + +value="$1" +shift + +while test $# -gt 1; do + test_value="$1" + shift + + set_value="$1" + shift + + if test x"$value" = x"$test_value" -o x"$test_value" = x"*"; then + echo "Setting $makevar=$set_value" + (echo ""; + if test x"$value" = x""; then + echo "# no $switch"; + elif test x"$value" = x"yes"; then + echo "# $switch"; + else + echo "# $switch=$value"; + fi + if test x"$set_value" = x""; then + echo "$makevar =" + else + echo "$makevar = $set_value" + fi) >> $make + exit 0; + fi +done + +if test x"$value" != x"" -a x"$value" != x"no"; then + echo "$switch=$value is not supported" 1>&2 + exit 1 +fi diff --git a/sim/ppc/configure b/sim/ppc/configure index ebf3a51eee..3b5059a0cc 100755 --- a/sim/ppc/configure +++ b/sim/ppc/configure @@ -1040,13 +1040,41 @@ rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 +if test x"$enable_sim_cflags" != x"" -a x"$enable_sim_cflags" != x"no"; then + if test "$enable_sim_cflags" = "yes"; then + enable_sim_cflags="-fomit-frame-pointer,-O2" + fi + echo "Setting SIM_CFLAGS=$enable_sim_cflags" | sed -e "s/,/ /g" 1>&6 + (echo; echo "# --enable-sim-cflags=$enable_sim_cflags"; + echo "SIM_CFLAGS = $enable_sim_cflags" | sed -e "s/,/ /g") >> Makefile +else + echo "Setting SIM_CFLAGS=" 1>&6 + (echo; echo "# no --enable-sim-cflags"; echo "SIM_CFLAGS =") >> Makefile +fi + +$srcdir/config.make Makefile CONFIG_FILE --enable-sim-config "$enable_sim_config" \ + "" "std-config.h" "no" "std-config.h" "yes" "std-config.h" "*" "$enable_sim_config" 1>&6 + +$srcdir/config.make Makefile IGEN_OPCODE_RULES --enable-sim-opcode "$enable_sim_opcode" \ + "" "ppc-opcode-simple" "no" "ppc-opcode-simple" "yes" "ppc-opcode-simple" \ + "complex" "ppc-opcode-complex" "simple" "ppc-opcode-simple" 1>&6 + +$srcdir/config.make Makefile DGEN_FLAGS --enable-sim-switch "$enable_sim_switch" \ + "" "" "no" "" "yes" "-s" 1>&6 + +$srcdir/config.make Makefile IGEN_DUPLICATE --enable-sim-duplicate "$enable_sim_duplicate" \ + "" "" "no" "" "yes" "-e" 1>&6 + +$srcdir/config.make Makefile IGEN_FILTER --enable-sim-filter "$enable_sim_filter" \ + "" "-f 64" "no" "" "yes" "-f 64" "*" "$enable_sim_filter" 1>&6 + +flags="" if test x"$enable_sim_inline" != x""; then - flags="" case "$enable_sim_inline" in no) flags="";; - 0) flags="-DDEFAULT_INLINE=0";; - yes | 2) flags="-DDEFAULT_INLINE=2";; - 1) flags="-DDEFAULT_INLINE=1";; + 0) flags=" -DDEFAULT_INLINE=0";; + yes | 2) flags=" -DDEFAULT_INLINE=2";; + 1) flags=" -DDEFAULT_INLINE=1";; *) for x in `echo "$enable_sim_inline" | sed -e "s/,/ /g"`; do case "$x" in *_INLINE=*) flags="$flags -D$x";; @@ -1056,87 +1084,68 @@ if test x"$enable_sim_inline" != x""; then esac done;; esac - if test x"$flags" != x""; then - mv Makefile Makefile.tem - echo "Setting INLINE_CFLAGS=$flags" 1>&6 - sed -e "s/^INLINE_CFLAGS.*=.*\$/INLINE_CFLAGS =$flags/" \ - < Makefile.tem > Makefile - rm -f Makefile.tem - fi fi - -if test x"$enable_sim_bswap" != x"" -a x"$enable_sim_bswap" != x"no"; then - mv Makefile Makefile.tem - echo "Setting BSWAP_CFLAGS=-DWITH_BSWAP=1" 1>&6 - sed -e "s/^BSWAP_CFLAGS.*=.*\$/BSWAP_CFLAGS = -DWITH_BSWAP=1/" \ - < Makefile.tem > Makefile - rm -f Makefile.tem -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 - -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 - -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 - -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 - -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 - +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 - 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 + echo "Setting INLINE_CFLAGS=" 1>&6 + (echo; echo "# no --enable-sim-inline"; echo "INLINE_CFLAGS =") >> Makefile fi -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;; +$srcdir/config.hdr config.h WITH_BSWAP --enable-sim-bswap "$enable_sim_bswap" "yes" 1 + +case "$target" in + *powerpc-*) endian="BIG_ENDIAN";; + *powerpcle-*) endian="LITTLE_ENDIAN";; + *) echo "Unknown $target" 1>&6; endian="0";; 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_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 + +$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 + +$srcdir/config.hdr config.h WITH_SMP --enable-sim-smp "$enable_sim_smp" \ + "" "0" "no" "0" "yes" "2" "*" "$enable_sim_smp" 1>&6 + +$srcdir/config.hdr config.h WITH_TARGET_WORD_BITSIZE --enable-sim-bitsize "$enable_sim_bitsize" \ + "yes" "32" "32" "32" "32" "64" "64" 1>&6 + +$srcdir/config.hdr config.h WITH_HOST_WORD_BITSIZE --enable-sim-hostbitsize "$enable_sim_hostbitsize" \ + "yes" "32" "32" "32" "32" "64" "64" 1>&6 + +$srcdir/config.hdr config.h WITH_ENVIRONMENT --enable-sim-env "$enable_sim_env" \ + "yes" "0" \ + "operating" "OPERATING_ENVIRONMENT" "os" "OPERATING_ENVIRONMENT" "oea" "OPERATING_ENVIRONMENT" \ + "virtual" "VIRTUAL_ENVIRONMENT" "vea" "VIRTUAL_ENVIRONMENT" 1>&6 + +$srcdir/config.hdr config.h WITH_TIME_BASE --enable-sim-timebase "$enable_sim_timebase" \ + "no" "0" "yes" "1" 1>&6 + +$srcdir/config.hdr config.h WITH_ALIGNMENT --enable-sim-alignment "$enable_sim_alignment" \ + "no" "NONSTRICT_ALIGNMENT" "nonstrict" "NONSTRICT_ALIGNMENT" \ + "yes" "STRICT_ALIGNMENT" "strict" "STRICT_ALIGNMENT" 1>&6 + +$srcdir/config.hdr config.h WITH_FLOATING_POINT --enable-sim-float "$enable_sim_float" \ + "no" "SOFT_FLOATING_POINT" "soft" "SOFT_FLOATING_POINT" \ + "yes" "HARD_FLOATING_POINT" "hard" "HARD_FLOATING_POINT" 1>&6 + +$srcdir/config.hdr config.h WITH_TRACE --enable-sim-trace "$enable_sim_trace" \ + "no" "0" "yes" "1" 1>&6 + +$srcdir/config.hdr config.h WITH_ASSERT --enable-sim-assert "$enable_sim_assert" \ + "no" "0" "yes" "1" 1>&6 + +$srcdir/config.hdr config.h WITH_MON --enable-sim-monitor "$enable_sim_monitor" \ + "no" "0" "yes" "MONITOR_INSTRUCTION_ISSUE|MONITOR_LOAD_STORE_UNIT" \ + "instruction" "MONITOR_INSTRUCTION_ISSUE" \ + "memory" "MONITOR_LOAD_STORE_UNIT" 1>&6 diff --git a/sim/ppc/configure.in b/sim/ppc/configure.in index 59bc4b2b2b..7b319f56ed 100644 --- a/sim/ppc/configure.in +++ b/sim/ppc/configure.in @@ -31,13 +31,41 @@ AC_CHECK_HEADERS(string.h strings.h stdlib.h time.h sys/times.h) AC_OUTPUT(Makefile, [case x$CONFIG_HEADERS in xconfig.h:config.in) echo > stamp-h ;; esac]) +if test x"$enable_sim_cflags" != x"" -a x"$enable_sim_cflags" != x"no"; then + if test "$enable_sim_cflags" = "yes"; then + enable_sim_cflags="-fomit-frame-pointer,-O2" + fi + echo "Setting SIM_CFLAGS=$enable_sim_cflags" | sed -e "s/,/ /g" 1>&6 + (echo; echo "# --enable-sim-cflags=$enable_sim_cflags"; + echo "SIM_CFLAGS = $enable_sim_cflags" | sed -e "s/,/ /g") >> Makefile +else + echo "Setting SIM_CFLAGS=" 1>&6 + (echo; echo "# no --enable-sim-cflags"; echo "SIM_CFLAGS =") >> Makefile +fi + +$srcdir/config.make Makefile CONFIG_FILE --enable-sim-config "$enable_sim_config" \ + "" "std-config.h" "no" "std-config.h" "yes" "std-config.h" "*" "$enable_sim_config" 1>&6 + +$srcdir/config.make Makefile IGEN_OPCODE_RULES --enable-sim-opcode "$enable_sim_opcode" \ + "" "ppc-opcode-simple" "no" "ppc-opcode-simple" "yes" "ppc-opcode-simple" \ + "complex" "ppc-opcode-complex" "simple" "ppc-opcode-simple" 1>&6 + +$srcdir/config.make Makefile DGEN_FLAGS --enable-sim-switch "$enable_sim_switch" \ + "" "" "no" "" "yes" "-s" 1>&6 + +$srcdir/config.make Makefile IGEN_DUPLICATE --enable-sim-duplicate "$enable_sim_duplicate" \ + "" "" "no" "" "yes" "-e" 1>&6 + +$srcdir/config.make Makefile IGEN_FILTER --enable-sim-filter "$enable_sim_filter" \ + "" "-f 64" "no" "" "yes" "-f 64" "*" "$enable_sim_filter" 1>&6 + +flags="" if test x"$enable_sim_inline" != x""; then - flags="" case "$enable_sim_inline" in no) flags="";; - 0) flags="-DDEFAULT_INLINE=0";; - yes | 2) flags="-DDEFAULT_INLINE=2";; - 1) flags="-DDEFAULT_INLINE=1";; + 0) flags=" -DDEFAULT_INLINE=0";; + yes | 2) flags=" -DDEFAULT_INLINE=2";; + 1) flags=" -DDEFAULT_INLINE=1";; *) for x in `echo "$enable_sim_inline" | sed -e "s/,/ /g"`; do case "$x" in *_INLINE=*) flags="$flags -D$x";; @@ -47,87 +75,68 @@ if test x"$enable_sim_inline" != x""; then esac done;; esac - if test x"$flags" != x""; then - mv Makefile Makefile.tem - echo "Setting INLINE_CFLAGS=$flags" 1>&6 - sed -e "s/^INLINE_CFLAGS.*=.*\$/INLINE_CFLAGS =$flags/" \ - < Makefile.tem > Makefile - rm -f Makefile.tem - fi fi - -if test x"$enable_sim_bswap" != x"" -a x"$enable_sim_bswap" != x"no"; then - mv Makefile Makefile.tem - echo "Setting BSWAP_CFLAGS=-DWITH_BSWAP=1" 1>&6 - sed -e "s/^BSWAP_CFLAGS.*=.*\$/BSWAP_CFLAGS = -DWITH_BSWAP=1/" \ - < Makefile.tem > Makefile - rm -f Makefile.tem -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 - -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 - -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 - -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 - -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 - +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 - 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 + echo "Setting INLINE_CFLAGS=" 1>&6 + (echo; echo "# no --enable-sim-inline"; echo "INLINE_CFLAGS =") >> Makefile fi -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;; +$srcdir/config.hdr config.h WITH_BSWAP --enable-sim-bswap "$enable_sim_bswap" "yes" 1 + +case "$target" in + *powerpc-*) endian="BIG_ENDIAN";; + *powerpcle-*) endian="LITTLE_ENDIAN";; + *) echo "Unknown $target" 1>&6; endian="0";; 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_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 + +$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 + +$srcdir/config.hdr config.h WITH_SMP --enable-sim-smp "$enable_sim_smp" \ + "" "0" "no" "0" "yes" "2" "*" "$enable_sim_smp" 1>&6 + +$srcdir/config.hdr config.h WITH_TARGET_WORD_BITSIZE --enable-sim-bitsize "$enable_sim_bitsize" \ + "yes" "32" "32" "32" "32" "64" "64" 1>&6 + +$srcdir/config.hdr config.h WITH_HOST_WORD_BITSIZE --enable-sim-hostbitsize "$enable_sim_hostbitsize" \ + "yes" "32" "32" "32" "32" "64" "64" 1>&6 + +$srcdir/config.hdr config.h WITH_ENVIRONMENT --enable-sim-env "$enable_sim_env" \ + "yes" "0" \ + "operating" "OPERATING_ENVIRONMENT" "os" "OPERATING_ENVIRONMENT" "oea" "OPERATING_ENVIRONMENT" \ + "virtual" "VIRTUAL_ENVIRONMENT" "vea" "VIRTUAL_ENVIRONMENT" 1>&6 + +$srcdir/config.hdr config.h WITH_TIME_BASE --enable-sim-timebase "$enable_sim_timebase" \ + "no" "0" "yes" "1" 1>&6 + +$srcdir/config.hdr config.h WITH_ALIGNMENT --enable-sim-alignment "$enable_sim_alignment" \ + "no" "NONSTRICT_ALIGNMENT" "nonstrict" "NONSTRICT_ALIGNMENT" \ + "yes" "STRICT_ALIGNMENT" "strict" "STRICT_ALIGNMENT" 1>&6 + +$srcdir/config.hdr config.h WITH_FLOATING_POINT --enable-sim-float "$enable_sim_float" \ + "no" "SOFT_FLOATING_POINT" "soft" "SOFT_FLOATING_POINT" \ + "yes" "HARD_FLOATING_POINT" "hard" "HARD_FLOATING_POINT" 1>&6 + +$srcdir/config.hdr config.h WITH_TRACE --enable-sim-trace "$enable_sim_trace" \ + "no" "0" "yes" "1" 1>&6 + +$srcdir/config.hdr config.h WITH_ASSERT --enable-sim-assert "$enable_sim_assert" \ + "no" "0" "yes" "1" 1>&6 + +$srcdir/config.hdr config.h WITH_MON --enable-sim-monitor "$enable_sim_monitor" \ + "no" "0" "yes" "MONITOR_INSTRUCTION_ISSUE|MONITOR_LOAD_STORE_UNIT" \ + "instruction" "MONITOR_INSTRUCTION_ISSUE" \ + "memory" "MONITOR_LOAD_STORE_UNIT" 1>&6 diff --git a/sim/ppc/debug.h b/sim/ppc/debug.h new file mode 100644 index 0000000000..b300addd09 --- /dev/null +++ b/sim/ppc/debug.h @@ -0,0 +1,118 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +#include "filter_filename.h" + +typedef enum { + trace_invalid, + trace_tbd, + /**/ + trace_gdb, + trace_os_emul, + /**/ + trace_device_tree, + trace_devices, + trace_pass_device, + trace_console_device, + trace_icu_device, + trace_halt_device, + trace_register_device, + trace_vm_device, + trace_memory_device, + trace_htab_device, + trace_pte_device, + trace_binary_device, + trace_file_device, + trace_core_device, + trace_stack_device, + /**/ + trace_semantics, + trace_idecode, + trace_alu, + /**/ + trace_vm, + trace_core, + trace_psim, + trace_device_init, + trace_cpu, + trace_breakpoint, + nr_trace_options +} trace_options; + + + +extern int ppc_trace[nr_trace_options]; + +#if WITH_TRACE +#define TRACE(OBJECT, ARGS) \ +do { \ + if (ppc_trace[OBJECT]) { \ + printf_filtered("%s:%d:%s: ", filter_filename(__FILE__), __LINE__, #OBJECT); \ + printf_filtered ARGS; \ + } \ +} while (0) +/* issue */ +#define ITRACE(OBJECT, ARGS) \ +do { \ + if (ppc_trace[OBJECT]) { \ + printf_filtered("%s:%d:0x%x", my_prefix, cpu_nr(processor) + 1, cia); \ + printf_filtered ARGS; \ + } \ +} while (0) +/* device */ +#define DTRACE(OBJECT, ARGS) \ +do { \ + if (ppc_trace[trace_devices] || ppc_trace[trace_##OBJECT##_device]) { \ + printf_filtered("%s:%d:%s: ", filter_filename(__FILE__), __LINE__, #OBJECT); \ + printf_filtered ARGS; \ + } \ +} while (0) +#else +#define TRACE(OBJECT, ARGS) +#define ITRACE(OBJECT, ARGS) +#define DTRACE(OBJECT, ARGS) +#endif + +#if WITH_ASSERT +#define ASSERT(EXPRESSION) \ +do { \ + if (!(EXPRESSION)) { \ + error("%s:%d: assertion failed - %s\n", \ + filter_filename(__FILE__), __LINE__, #EXPRESSION); \ + } \ +} while (0) +#else +#define ASSERT(EXPRESSION) +#endif + +/* Parse OPTION updating the trace array */ +extern void +trace_option(const char *option); + +/* Output the list of trace options */ +extern void +trace_usage(void); + + +#endif /* _DEBUG_H_ */ diff --git a/sim/ppc/emul_netbsd.c b/sim/ppc/emul_netbsd.c new file mode 100644 index 0000000000..e7d09c31b0 --- /dev/null +++ b/sim/ppc/emul_netbsd.c @@ -0,0 +1,1202 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WITH_NetBSD_HOST (NetBSD >= 199306) +#if WITH_NetBSD_HOST /* here NetBSD as that is what we're emulating */ +#include /* FIXME - should not be including this one */ +#include +extern int getdirentries(int fd, char *buf, int nbytes, long *basep); +#endif + +#if (BSD < 199306) /* here BSD as just a bug */ +extern int errno; +#endif + +#include "emul_generic.h" + + +#ifndef STATIC_INLINE_EMUL_NETBSD +#define STATIC_INLINE_EMUL_NETBSD STATIC_INLINE +#endif + + +#if WITH_NetBSD_HOST +#define SYS(X) ASSERT(call == (SYS_##X)) +#else +#define SYS(X) +#endif + +#if WITH_NetBSD_HOST && (PATH_MAX != 1024) +#error "PATH_MAX not 1024" +#elif !defined(PATH_MAX) +#define PATH_MAX 1024 +#endif + + +STATIC_INLINE_EMUL_NETBSD void +write_stat(unsigned_word addr, + struct stat buf, + cpu *processor, + unsigned_word cia) +{ + H2T(buf.st_dev); + H2T(buf.st_ino); + H2T(buf.st_mode); + H2T(buf.st_nlink); + H2T(buf.st_uid); + H2T(buf.st_gid); + H2T(buf.st_rdev); + H2T(buf.st_size); + H2T(buf.st_atime); + /* H2T(buf.st_spare1); */ + H2T(buf.st_mtime); + /* H2T(buf.st_spare2); */ + H2T(buf.st_ctime); + /* H2T(buf.st_spare3); */ + H2T(buf.st_blksize); + H2T(buf.st_blocks); +#if WITH_NetBSD_HOST + H2T(buf.st_flags); + H2T(buf.st_gen); +#endif + emul_write_buffer(&buf, addr, sizeof(buf), processor, cia); +} + + +#if NetBSD +STATIC_INLINE_EMUL_NETBSD void +write_statfs(unsigned_word addr, + struct statfs buf, + cpu *processor, + unsigned_word cia) +{ + H2T(buf.f_type); + H2T(buf.f_flags); + H2T(buf.f_bsize); + H2T(buf.f_iosize); + H2T(buf.f_blocks); + H2T(buf.f_bfree); + H2T(buf.f_bavail); + H2T(buf.f_files); + H2T(buf.f_ffree); + H2T(buf.f_fsid.val[0]); + H2T(buf.f_fsid.val[1]); + H2T(buf.f_owner); + /* f_spare[4]; */ + /* f_fstypename[MFSNAMELEN]; */ + /* f_mntonname[MNAMELEN]; */ + /* f_mntfromname[MNAMELEN]; */ + emul_write_buffer(&buf, addr, sizeof(buf), processor, cia); +} +#endif + + +STATIC_INLINE_EMUL_NETBSD void +write_timeval(unsigned_word addr, + struct timeval t, + cpu *processor, + unsigned_word cia) +{ + H2T(t.tv_sec); + H2T(t.tv_usec); + emul_write_buffer(&t, addr, sizeof(t), processor, cia); +} + + +STATIC_INLINE_EMUL_NETBSD void +write_timezone(unsigned_word addr, + struct timezone tz, + cpu *processor, + unsigned_word cia) +{ + H2T(tz.tz_minuteswest); + H2T(tz.tz_dsttime); + emul_write_buffer(&tz, addr, sizeof(tz), processor, cia); +} + + +#if WITH_NetBSD_HOST +STATIC_INLINE_EMUL_NETBSD void +write_direntries(unsigned_word addr, + char *buf, + int nbytes, + cpu *processor, + unsigned_word cia) +{ + while (nbytes > 0) { + struct dirent *out; + struct dirent *in = (struct dirent*)buf; + ASSERT(in->d_reclen <= nbytes); + out = (struct dirent*)zalloc(in->d_reclen); + bcopy(in, out, in->d_reclen); + H2T(out->d_fileno); + H2T(out->d_reclen); + H2T(out->d_type); + H2T(out->d_namlen); + emul_write_buffer(out, addr, in->d_reclen, processor, cia); + nbytes -= in->d_reclen; + addr += in->d_reclen; + buf += in->d_reclen; + zfree(out); + } +} +#endif + + +STATIC_INLINE_EMUL_NETBSD void +write_rusage(unsigned_word addr, + struct rusage rusage, + cpu *processor, + unsigned_word cia) +{ + H2T(rusage.ru_utime.tv_sec); /* user time used */ + H2T(rusage.ru_utime.tv_usec); + H2T(rusage.ru_stime.tv_sec); /* system time used */ + H2T(rusage.ru_stime.tv_usec); + H2T(rusage.ru_maxrss); /* integral max resident set size */ + H2T(rusage.ru_ixrss); /* integral shared text memory size */ + H2T(rusage.ru_idrss); /* integral unshared data size */ + H2T(rusage.ru_isrss); /* integral unshared stack size */ + H2T(rusage.ru_minflt); /* page reclaims */ + H2T(rusage.ru_majflt); /* page faults */ + H2T(rusage.ru_nswap); /* swaps */ + H2T(rusage.ru_inblock); /* block input operations */ + H2T(rusage.ru_oublock); /* block output operations */ + H2T(rusage.ru_msgsnd); /* messages sent */ + H2T(rusage.ru_msgrcv); /* messages received */ + H2T(rusage.ru_nsignals); /* signals received */ + H2T(rusage.ru_nvcsw); /* voluntary context switches */ + H2T(rusage.ru_nivcsw); /* involuntary context switches */ + emul_write_buffer(&rusage, addr, sizeof(rusage), processor, cia); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_exit(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + int status = (int)cpu_registers(processor)->gpr[arg0]; + SYS(exit); + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("%d)\n", status); + + cpu_halt(processor, cia, was_exited, status); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_read(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + void *scratch_buffer; + int d = (int)cpu_registers(processor)->gpr[arg0]; + unsigned_word buf = cpu_registers(processor)->gpr[arg0+1]; + int nbytes = cpu_registers(processor)->gpr[arg0+2]; + int status; + int nr_moved; + SYS(read); + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("%d, 0x%lx, %d", d, (long)buf, nbytes); + + /* get a tempoary bufer */ + scratch_buffer = zalloc(nbytes); + + /* check if buffer exists by reading it */ + emul_read_buffer(scratch_buffer, buf, nbytes, processor, cia); + + /* read */ +#if 0 + if (d == 0) { + status = fread (scratch_buffer, 1, nbytes, stdin); + if (status == 0 && ferror (stdin)) + status = -1; + } +#endif + status = read (d, scratch_buffer, nbytes); + + if (status == -1) { + cpu_registers(processor)->gpr[0] = errno; + } else { + cpu_registers(processor)->gpr[3] = status; + + if (status > 0) + emul_write_buffer(scratch_buffer, buf, status, processor, cia); + } + + zfree(scratch_buffer); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_write(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + void *scratch_buffer = NULL; + int nr_moved; + int d = (int)cpu_registers(processor)->gpr[arg0]; + unsigned_word buf = cpu_registers(processor)->gpr[arg0+1]; + int nbytes = cpu_registers(processor)->gpr[arg0+2]; + int status; + SYS(write); + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("%d, 0x%lx, %d", d, (long)buf, nbytes); + + /* get a tempoary bufer */ + scratch_buffer = zalloc(nbytes); /* FIXME - nbytes == 0 */ + + /* copy in */ + nr_moved = vm_data_map_read_buffer(cpu_data_map(processor), + scratch_buffer, + buf, + nbytes); + if (nr_moved != nbytes) { + /* FIXME - should handle better */ + error("system_call()write copy failed (nr_moved=%d != nbytes=%d)\n", + nr_moved, nbytes); + } + + /* write */ + status = write(d, scratch_buffer, nbytes); + emul_write_status(processor, status, errno); + zfree(scratch_buffer); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_open(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + unsigned_word path_addr = cpu_registers(processor)->gpr[arg0]; + char path_buf[PATH_MAX]; + char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia); + int flags = (int)cpu_registers(processor)->gpr[arg0+1]; + int mode = (int)cpu_registers(processor)->gpr[arg0+2]; + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("0x%lx [%s], 0x%x, 0x%x", (long)path_addr, path, flags, mode); + + SYS(open); + emul_write_status(processor, open(path, flags, mode), errno); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_close(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + int d = (int)cpu_registers(processor)->gpr[arg0]; + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("%d", d); + + SYS(close); + emul_write_status(processor, close(d), errno); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_break(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) + /* just pass this onto the `vm' device */ +{ + psim *system = cpu_system(processor); + const device *vm = psim_device(system, "/vm"); + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("0x%lx", (long)cpu_registers(processor)->gpr[arg0]); + + SYS(break); + vm->callback->ioctl(vm, + system, + processor, + cia, + 0, /*ioctl*/ + NULL); /*ioctl-data*/ +} + + +STATIC_INLINE_EMUL_NETBSD void +do_getpid(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + SYS(getpid); + cpu_registers(processor)->gpr[3] = (int)getpid(); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_getuid(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + SYS(getuid); + cpu_registers(processor)->gpr[3] = (int)getuid(); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_geteuid(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + SYS(geteuid); + cpu_registers(processor)->gpr[3] = (int)geteuid(); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_kill(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + pid_t pid = cpu_registers(processor)->gpr[arg0]; + int sig = cpu_registers(processor)->gpr[arg0+1]; + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("%d, %d", (int)pid, sig); + + SYS(kill); + printf_filtered("SYS_kill at 0x%x - more to this than just being killed\n", + cia); + cpu_halt(processor, cia, was_signalled, sig); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_dup(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + int oldd = cpu_registers(processor)->gpr[arg0]; + int status = dup(oldd); + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("%d", oldd); + + SYS(dup); + emul_write_status(processor, status, errno); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_getegid(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + SYS(getegid); + cpu_registers(processor)->gpr[3] = (int)getegid(); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_getgid(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + SYS(getgid); + cpu_registers(processor)->gpr[3] = (int)getgid(); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_sigprocmask(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + natural_word how = cpu_registers(processor)->gpr[arg0]; + unsigned_word set = cpu_registers(processor)->gpr[arg0+1]; + unsigned_word oset = cpu_registers(processor)->gpr[arg0+2]; + SYS(sigprocmask); + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("%ld, 0x%ld, 0x%ld", (long)how, (long)set, (long)oset); + + cpu_registers(processor)->gpr[3] = 0; + cpu_registers(processor)->gpr[4] = set; +} + + +STATIC_INLINE_EMUL_NETBSD void +do_ioctl(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + int d = cpu_registers(processor)->gpr[arg0]; + unsigned request = cpu_registers(processor)->gpr[arg0+1]; + unsigned_word argp_addr = cpu_registers(processor)->gpr[arg0+2]; + +#if !WITH_NetBSD_HOST + cpu_registers(processor)->gpr[arg0] = 0; /* just succeed */ +#else + unsigned param_len = IOCPARM_LEN(request); + unsigned basecmd = IOCBASECMD(request); + unsigned group = IOCGROUP(request); + unsigned dir = request & IOC_DIRMASK; + char *argp = NULL; + int status; + SYS(ioctl); + /* what we haven't done */ + if (dir & IOC_IN /* write into the io device */ + || dir & IOC_OUT + || !(dir & IOC_VOID)) + error("do_ioctl() read or write of parameter not implemented\n"); + status = ioctl(d, request, NULL); + emul_write_status(processor, status, errno); +#endif + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("%d, 0x%x, 0x%lx", d, request, (long)argp_addr); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_umask(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + int mask = cpu_registers(processor)->gpr[arg0]; + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("0%o", mask); + + SYS(umask); + cpu_registers(processor)->gpr[3] = umask(mask); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_dup2(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + int oldd = cpu_registers(processor)->gpr[arg0]; + int newd = cpu_registers(processor)->gpr[arg0+1]; + int status = dup2(oldd, newd); + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("%d, %d", oldd, newd); + + SYS(dup2); + emul_write_status(processor, status, errno); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_fcntl(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + int fd = cpu_registers(processor)->gpr[arg0]; + int cmd = cpu_registers(processor)->gpr[arg0+1]; + int arg = cpu_registers(processor)->gpr[arg0+2]; + int status; + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("%d, %d, %d", fd, cmd, arg); + + SYS(fcntl); + status = fcntl(fd, cmd, arg); + emul_write_status(processor, status, errno); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_gettimeofday(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + unsigned_word t_addr = cpu_registers(processor)->gpr[arg0]; + unsigned_word tz_addr = cpu_registers(processor)->gpr[arg0+1]; + struct timeval t; + struct timezone tz; + int status = gettimeofday((t_addr != 0 ? &t : NULL), + (tz_addr != 0 ? &tz : NULL)); + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("0x%lx, 0x%lx", (long)t_addr, (long)tz_addr); + + SYS(gettimeofday); + emul_write_status(processor, status, errno); + if (status == 0) { + if (t_addr != 0) + write_timeval(t_addr, t, processor, cia); + if (tz_addr != 0) + write_timezone(tz_addr, tz, processor, cia); + } +} + + +STATIC_INLINE_EMUL_NETBSD void +do_getrusage(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + int who = cpu_registers(processor)->gpr[arg0]; + unsigned_word rusage_addr = cpu_registers(processor)->gpr[arg0+1]; + struct rusage rusage; + int status = getrusage(who, (rusage_addr != 0 ? &rusage : NULL)); + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("%d, 0x%lx", who, (long)rusage_addr); + + SYS(getrusage); + emul_write_status(processor, status, errno); + if (status == 0) { + if (rusage_addr != 0) + write_rusage(rusage_addr, rusage, processor, cia); + } +} + + +#if !WITH_NetBSD_HOST +#define do_fstatfs 0 +#else +STATIC_INLINE_EMUL_NETBSD void +do_fstatfs(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + int fd = cpu_registers(processor)->gpr[arg0]; + unsigned_word buf_addr = cpu_registers(processor)->gpr[arg0+1]; + struct statfs buf; + int status; + + if (WITH_TRACE && ppc_trace[trace_os_emul]) + printf_filtered ("%d, 0x%lx", fd, (long)buf_addr); + + SYS(fstatfs); + status = fstatfs(fd, (buf_addr == 0 ? NULL : &buf)); + emul_write_status(processor, status, errno); + if (status == 0) { + if (buf_addr != 0) + write_statfs(buf_addr, buf, processor, cia); + } +} +#endif + + +STATIC_INLINE_EMUL_NETBSD void +do_stat(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + char path_buf[PATH_MAX]; + unsigned_word path_addr = cpu_registers(processor)->gpr[arg0]; + unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[arg0+1]; + char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia); + struct stat buf; + int status; + SYS(stat); + status = stat(path, &buf); + emul_write_status(processor, status, errno); + if (status == 0) + write_stat(stat_buf_addr, buf, processor, cia); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_fstat(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + int fd = cpu_registers(processor)->gpr[arg0]; + unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[arg0+1]; + struct stat buf; + SYS(fstat); + emul_write_status(processor, fstat(fd, &buf), errno); + write_stat(stat_buf_addr, buf, processor, cia); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_lstat(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + char path_buf[PATH_MAX]; + unsigned_word path_addr = cpu_registers(processor)->gpr[arg0]; + char *path = emul_read_string(path_buf, path_addr, PATH_MAX, processor, cia); + unsigned_word stat_buf_addr = cpu_registers(processor)->gpr[arg0+1]; + struct stat buf; + SYS(lstat); + emul_write_status(processor, stat(path, &buf), errno); + write_stat(stat_buf_addr, buf, processor, cia); +} + + +#if !WITH_NetBSD_HOST +#define do_getdirentries 0 +#else +STATIC_INLINE_EMUL_NETBSD void +do_getdirentries(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + int fd = cpu_registers(processor)->gpr[arg0]; + unsigned_word buf_addr = cpu_registers(processor)->gpr[arg0+1]; + char *buf; + int nbytes = cpu_registers(processor)->gpr[arg0+2]; + unsigned_word basep_addr = cpu_registers(processor)->gpr[arg0+3]; + long basep; + int status; + SYS(getdirentries); + if (buf_addr != 0 && nbytes >= 0) + buf = zalloc(nbytes); + else + buf = NULL; + status = getdirentries(fd, + (buf_addr == 0 ? NULL : buf), + nbytes, + (basep_addr == 0 ? NULL : &basep)); + emul_write_status(processor, status, errno); + if (basep_addr != 0) + emul_write_word(basep_addr, basep, processor, cia); + if (status > 0) + write_direntries(buf_addr, buf, status, processor, cia); + if (buf != NULL) + zfree(buf); +} +#endif + + +STATIC_INLINE_EMUL_NETBSD void +do___syscall(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + SYS(__syscall); + emul_do_call(emul, + cpu_registers(processor)->gpr[arg0], + arg0 + 1, + processor, + cia); +} + + +STATIC_INLINE_EMUL_NETBSD void +do_lseek(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + int fildes = cpu_registers(processor)->gpr[arg0]; + off_t offset = emul_read_gpr64(processor, arg0+2); + int whence = cpu_registers(processor)->gpr[arg0+4]; + off_t status; + SYS(lseek); + status = lseek(fildes, offset, whence); + if (status == -1) + emul_write_status(processor, -1, errno); + else { + emul_write_gpr64(processor, 3, status); + } +} + + +STATIC_INLINE_EMUL_NETBSD void +do___sysctl(emulation *emul, + unsigned call, + const int arg0, + cpu *processor, + unsigned_word cia) +{ + /* call the arguments by their real name */ + unsigned_word name = cpu_registers(processor)->gpr[arg0]; + natural_word namelen = cpu_registers(processor)->gpr[arg0+1]; + unsigned_word oldp = cpu_registers(processor)->gpr[arg0+2]; + unsigned_word oldlenp = cpu_registers(processor)->gpr[arg0+3]; + natural_word oldlen; + natural_word mib; + natural_word int_val; + SYS(__sysctl); + + /* pluck out the management information base id */ + if (namelen < 1) + error("system_call()SYS___sysctl bad name[0]\n"); + mib = vm_data_map_read_word(cpu_data_map(processor), + name, + processor, + cia); + name += sizeof(mib); + + /* see what to do with it ... */ + switch (mib) { + case 6/*CTL_HW*/: +#if WITH_NetBSD_HOST && (CTL_HW != 6) +# error "CTL_HW" +#endif + if (namelen < 2) + error("system_call()SYS___sysctl - CTL_HW - bad name[1]\n"); + mib = vm_data_map_read_word(cpu_data_map(processor), + name, + processor, + cia); + name += sizeof(mib); + switch (mib) { + case 7/*HW_PAGESIZE*/: +#if WITH_NetBSD_HOST && (HW_PAGESIZE != 7) +# error "HW_PAGESIZE" +#endif + oldlen = vm_data_map_read_word(cpu_data_map(processor), + oldlenp, + processor, + cia); + if (sizeof(natural_word) > oldlen) + error("system_call()sysctl - CTL_HW.HW_PAGESIZE - to small\n"); + int_val = 8192; + oldlen = sizeof(int_val); + emul_write_word(oldp, int_val, processor, cia); + emul_write_word(oldlenp, oldlen, processor, cia); + break; + default: + error("sysctl() CTL_HW.%d unknown\n", mib); + break; + } + break; + default: + error("sysctl() name[0]=%s unknown\n", (int)mib); + break; + } + cpu_registers(processor)->gpr[3] = 0; +} + + + +static emul_call_descriptor netbsd_descriptors[] = { + /* 0 */ { 0, "syscall", { 0, }, 0 }, + /* 1 */ { do_exit, "exit", { 0, }, 0 }, + /* 2 */ { 0, "fork", { 0, }, 0 }, + /* 3 */ { do_read, "read", { 0, }, 0 }, + /* 4 */ { do_write, "write", { 0, }, 0 }, + /* 5 */ { do_open, "open", { 0, }, 0 }, + /* 6 */ { do_close, "close", { 0, }, 0 }, + /* 7 */ { 0, "wait4", { 0, }, 0 }, + { 0, }, /* 8 is old creat */ + /* 9 */ { 0, "link", { 0, }, 0 }, + /* 10 */ { 0, "unlink", { 0, }, 0 }, + { 0, }, /* 11 is obsolete execv */ + /* 12 */ { 0, "chdir", { 0, }, 0 }, + /* 13 */ { 0, "fchdir", { 0, }, 0 }, + /* 14 */ { 0, "mknod", { 0, }, 0 }, + /* 15 */ { 0, "chmod", { 0, }, 0 }, + /* 16 */ { 0, "chown", { 0, }, 0 }, + /* 17 */ { do_break, "break", { 0, }, 0 }, + /* 18 */ { 0, "getfsstat", { 0, }, 0 }, + { 0, }, /* 19 is old lseek */ + /* 20 */ { do_getpid, "getpid", { 0, }, 0 }, + /* 21 */ { 0, "mount", { 0, }, 0 }, + /* 22 */ { 0, "unmount", { 0, }, 0 }, + /* 23 */ { 0, "setuid", { 0, }, 0 }, + /* 24 */ { do_getuid, "getuid", { 0, }, 0 }, + /* 25 */ { do_geteuid, "geteuid", { 0, }, 0 }, + /* 26 */ { 0, "ptrace", { 0, }, 0 }, + /* 27 */ { 0, "recvmsg", { 0, }, 0 }, + /* 28 */ { 0, "sendmsg", { 0, }, 0 }, + /* 29 */ { 0, "recvfrom", { 0, }, 0 }, + /* 30 */ { 0, "accept", { 0, }, 0 }, + /* 31 */ { 0, "getpeername", { 0, }, 0 }, + /* 32 */ { 0, "getsockname", { 0, }, 0 }, + /* 33 */ { 0, "access", { 0, }, 0 }, + /* 34 */ { 0, "chflags", { 0, }, 0 }, + /* 35 */ { 0, "fchflags", { 0, }, 0 }, + /* 36 */ { 0, "sync", { 0, }, 0 }, + /* 37 */ { do_kill, "kill", { 0, }, 0 }, + { 0, }, /* 38 is old stat */ + /* 39 */ { 0, "getppid", { 0, }, 0 }, + { 0, }, /* 40 is old lstat */ + /* 41 */ { do_dup, "dup", { 0, }, 0 }, + /* 42 */ { 0, "pipe", { 0, }, 0 }, + /* 43 */ { do_getegid, "getegid", { 0, }, 0 }, + /* 44 */ { 0, "profil", { 0, }, 0 }, + /* 45 */ { 0, "ktrace", { 0, }, 0 }, + /* 46 */ { 0, "sigaction", { 0, }, 0 }, + /* 47 */ { do_getgid, "getgid", { 0, }, 0 }, + /* 48 */ { do_sigprocmask, "sigprocmask", { 0, }, 0 }, + /* 49 */ { 0, "getlogin", { 0, }, 0 }, + /* 50 */ { 0, "setlogin", { 0, }, 0 }, + /* 51 */ { 0, "acct", { 0, }, 0 }, + /* 52 */ { 0, "sigpending", { 0, }, 0 }, + /* 53 */ { 0, "sigaltstack", { 0, }, 0 }, + /* 54 */ { do_ioctl, "ioctl", { 0, }, 0 }, + /* 55 */ { 0, "reboot", { 0, }, 0 }, + /* 56 */ { 0, "revoke", { 0, }, 0 }, + /* 57 */ { 0, "symlink", { 0, }, 0 }, + /* 58 */ { 0, "readlink", { 0, }, 0 }, + /* 59 */ { 0, "execve", { 0, }, 0 }, + /* 60 */ { do_umask, "umask", { 0, }, 0 }, + /* 61 */ { 0, "chroot", { 0, }, 0 }, + { 0, }, /* 62 is old fstat */ + { 0, }, /* 63 is old getkerninfo */ + { 0, }, /* 64 is old getpagesize */ + /* 65 */ { 0, "msync", { 0, }, 0 }, + /* 66 */ { 0, "vfork", { 0, }, 0 }, + { 0, }, /* 67 is obsolete vread */ + { 0, }, /* 68 is obsolete vwrite */ + /* 69 */ { 0, "sbrk", { 0, }, 0 }, + /* 70 */ { 0, "sstk", { 0, }, 0 }, + { 0, }, /* 71 is old mmap */ + /* 72 */ { 0, "vadvise", { 0, }, 0 }, + /* 73 */ { 0, "munmap", { 0, }, 0 }, + /* 74 */ { 0, "mprotect", { 0, }, 0 }, + /* 75 */ { 0, "madvise", { 0, }, 0 }, + { 0, }, /* 76 is obsolete vhangup */ + { 0, }, /* 77 is obsolete vlimit */ + /* 78 */ { 0, "mincore", { 0, }, 0 }, + /* 79 */ { 0, "getgroups", { 0, }, 0 }, + /* 80 */ { 0, "setgroups", { 0, }, 0 }, + /* 81 */ { 0, "getpgrp", { 0, }, 0 }, + /* 82 */ { 0, "setpgid", { 0, }, 0 }, + /* 83 */ { 0, "setitimer", { 0, }, 0 }, + { 0, }, /* 84 is old wait */ + /* 85 */ { 0, "swapon", { 0, }, 0 }, + /* 86 */ { 0, "getitimer", { 0, }, 0 }, + { 0, }, /* 87 is old gethostname */ + { 0, }, /* 88 is old sethostname */ + { 0, }, /* 89 is old getdtablesize */ + { do_dup2, "dup2", { 0, }, 0 }, + { 0, }, /* 91 */ + /* 92 */ { do_fcntl, "fcntl", { 0, }, 0 }, + /* 93 */ { 0, "select", { 0, }, 0 }, + { 0, }, /* 94 */ + /* 95 */ { 0, "fsync", { 0, }, 0 }, + /* 96 */ { 0, "setpriority", { 0, }, 0 }, + /* 97 */ { 0, "socket", { 0, }, 0 }, + /* 98 */ { 0, "connect", { 0, }, 0 }, + { 0, }, /* 99 is old accept */ + /* 100 */ { 0, "getpriority", { 0, }, 0 }, + { 0, }, /* 101 is old send */ + { 0, }, /* 102 is old recv */ + /* 103 */ { 0, "sigreturn", { 0, }, 0 }, + /* 104 */ { 0, "bind", { 0, }, 0 }, + /* 105 */ { 0, "setsockopt", { 0, }, 0 }, + /* 106 */ { 0, "listen", { 0, }, 0 }, + { 0, }, /* 107 is obsolete vtimes */ + { 0, }, /* 108 is old sigvec */ + { 0, }, /* 109 is old sigblock */ + { 0, }, /* 110 is old sigsetmask */ + /* 111 */ { 0, "sigsuspend", { 0, }, 0 }, + { 0, }, /* 112 is old sigstack */ + { 0, }, /* 113 is old recvmsg */ + { 0, }, /* 114 is old sendmsg */ + /* - is obsolete vtrace */ { 0, "vtrace 115", { 0, }, 0 }, + /* 116 */ { do_gettimeofday, "gettimeofday", { 0, }, 0 }, + /* 117 */ { do_getrusage, "getrusage", { 0, }, 0 }, + /* 118 */ { 0, "getsockopt", { 0, }, 0 }, + /* 119 */ { 0, "resuba", { 0, }, 0 }, + /* 120 */ { 0, "readv", { 0, }, 0 }, + /* 121 */ { 0, "writev", { 0, }, 0 }, + /* 122 */ { 0, "settimeofday", { 0, }, 0 }, + /* 123 */ { 0, "fchown", { 0, }, 0 }, + /* 124 */ { 0, "fchmod", { 0, }, 0 }, + { 0, }, /* 125 is old recvfrom */ + { 0, }, /* 126 is old setreuid */ + { 0, }, /* 127 is old setregid */ + /* 128 */ { 0, "rename", { 0, }, 0 }, + { 0, }, /* 129 is old truncate */ + { 0, }, /* 130 is old ftruncate */ + /* 131 */ { 0, "flock", { 0, }, 0 }, + /* 132 */ { 0, "mkfifo", { 0, }, 0 }, + /* 133 */ { 0, "sendto", { 0, }, 0 }, + /* 134 */ { 0, "shutdown", { 0, }, 0 }, + /* 135 */ { 0, "socketpair", { 0, }, 0 }, + /* 136 */ { 0, "mkdir", { 0, }, 0 }, + /* 137 */ { 0, "rmdir", { 0, }, 0 }, + /* 138 */ { 0, "utimes", { 0, }, 0 }, + { 0, }, /* 139 is obsolete 4.2 sigreturn */ + /* 140 */ { 0, "adjtime", { 0, }, 0 }, + { 0, }, /* 141 is old getpeername */ + { 0, }, /* 142 is old gethostid */ + { 0, }, /* 143 is old sethostid */ + { 0, }, /* 144 is old getrlimit */ + { 0, }, /* 145 is old setrlimit */ + { 0, }, /* 146 is old killpg */ + /* 147 */ { 0, "setsid", { 0, }, 0 }, + /* 148 */ { 0, "quotactl", { 0, }, 0 }, + { 0, }, /* 149 is old quota */ + { 0, }, /* 150 is old getsockname */ + { 0, }, /* 151 */ + { 0, }, /* 152 */ + { 0, }, /* 153 */ + { 0, }, /* 154 */ + /* 155 */ { 0, "nfssvc", { 0, }, 0 }, + { 0, }, /* 156 is old getdirentries */ + /* 157 */ { 0, "statfs", { 0, }, 0 }, + /* 158 */ { do_fstatfs, "fstatfs", { 0, }, 0 }, + { 0, }, /* 159 */ + { 0, }, /* 160 */ + /* 161 */ { 0, "getfh", { 0, }, 0 }, + { 0, }, /* 162 is old getdomainname */ + { 0, }, /* 163 is old setdomainname */ + { 0, }, /* 164 is old uname */ + /* 165 */ { 0, "sysarch", { 0, }, 0 }, + { 0, }, /* 166 */ + { 0, }, /* 167 */ + { 0, }, /* 168 */ + /* 169 */ { 0, "semsys", { 0, }, 0 }, + /* 170 */ { 0, "msgsys", { 0, }, 0 }, + /* 171 */ { 0, "shmsys", { 0, }, 0 }, + { 0, }, /* 172 */ + { 0, }, /* 173 */ + { 0, }, /* 174 */ + { 0, }, /* 175 */ + { 0, }, /* 176 */ + { 0, }, /* 177 */ + { 0, }, /* 178 */ + { 0, }, /* 179 */ + { 0, }, /* 180 */ + /* 181 */ { 0, "setgid", { 0, }, 0 }, + /* 182 */ { 0, "setegid", { 0, }, 0 }, + /* 183 */ { 0, "seteuid", { 0, }, 0 }, + /* 184 */ { 0, "lfs_bmapv", { 0, }, 0 }, + /* 185 */ { 0, "lfs_markv", { 0, }, 0 }, + /* 186 */ { 0, "lfs_segclean", { 0, }, 0 }, + /* 187 */ { 0, "lfs_segwait", { 0, }, 0 }, + /* 188 */ { do_stat, "stat", { 0, }, 0 }, + /* 189 */ { do_fstat, "fstat", { 0, }, 0 }, + /* 190 */ { do_lstat, "lstat", { 0, }, 0 }, + /* 191 */ { 0, "pathconf", { 0, }, 0 }, + /* 192 */ { 0, "fpathconf", { 0, }, 0 }, + { 0, }, /* 193 */ + /* 194 */ { 0, "getrlimit", { 0, }, 0 }, + /* 195 */ { 0, "setrlimit", { 0, }, 0 }, + /* 196 */ { do_getdirentries, "getdirentries", { 0, }, 0 }, + /* 197 */ { 0, "mmap", { 0, }, 0 }, + /* 198 */ { do___syscall, "__syscall", { 0, }, 0 }, + /* 199 */ { do_lseek, "lseek", { 0, }, 0 }, + /* 200 */ { 0, "truncate", { 0, }, 0 }, + /* 201 */ { 0, "ftruncate", { 0, }, 0 }, + /* 202 */ { do___sysctl, "__sysctl", { 0, }, 0 }, + /* 203 */ { 0, "mlock", { 0, }, 0 }, + /* 204 */ { 0, "munlock", { 0, }, 0 }, +}; + +static char *(netbsd_error_names[]) = { + /* 0 */ "ESUCCESS", + /* 1 */ "EPERM", + /* 2 */ "ENOENT", + /* 3 */ "ESRCH", + /* 4 */ "EINTR", + /* 5 */ "EIO", + /* 6 */ "ENXIO", + /* 7 */ "E2BIG", + /* 8 */ "ENOEXEC", + /* 9 */ "EBADF", + /* 10 */ "ECHILD", + /* 11 */ "EDEADLK", + /* 12 */ "ENOMEM", + /* 13 */ "EACCES", + /* 14 */ "EFAULT", + /* 15 */ "ENOTBLK", + /* 16 */ "EBUSY", + /* 17 */ "EEXIST", + /* 18 */ "EXDEV", + /* 19 */ "ENODEV", + /* 20 */ "ENOTDIR", + /* 21 */ "EISDIR", + /* 22 */ "EINVAL", + /* 23 */ "ENFILE", + /* 24 */ "EMFILE", + /* 25 */ "ENOTTY", + /* 26 */ "ETXTBSY", + /* 27 */ "EFBIG", + /* 28 */ "ENOSPC", + /* 29 */ "ESPIPE", + /* 30 */ "EROFS", + /* 31 */ "EMLINK", + /* 32 */ "EPIPE", + /* 33 */ "EDOM", + /* 34 */ "ERANGE", + /* 35 */ "EAGAIN", + /* 36 */ "EINPROGRESS", + /* 37 */ "EALREADY", + /* 38 */ "ENOTSOCK", + /* 39 */ "EDESTADDRREQ", + /* 40 */ "EMSGSIZE", + /* 41 */ "EPROTOTYPE", + /* 42 */ "ENOPROTOOPT", + /* 43 */ "EPROTONOSUPPORT", + /* 44 */ "ESOCKTNOSUPPORT", + /* 45 */ "EOPNOTSUPP", + /* 46 */ "EPFNOSUPPORT", + /* 47 */ "EAFNOSUPPORT", + /* 48 */ "EADDRINUSE", + /* 49 */ "EADDRNOTAVAIL", + /* 50 */ "ENETDOWN", + /* 51 */ "ENETUNREACH", + /* 52 */ "ENETRESET", + /* 53 */ "ECONNABORTED", + /* 54 */ "ECONNRESET", + /* 55 */ "ENOBUFS", + /* 56 */ "EISCONN", + /* 57 */ "ENOTCONN", + /* 58 */ "ESHUTDOWN", + /* 59 */ "ETOOMANYREFS", + /* 60 */ "ETIMEDOUT", + /* 61 */ "ECONNREFUSED", + /* 62 */ "ELOOP", + /* 63 */ "ENAMETOOLONG", + /* 64 */ "EHOSTDOWN", + /* 65 */ "EHOSTUNREACH", + /* 66 */ "ENOTEMPTY", + /* 67 */ "EPROCLIM", + /* 68 */ "EUSERS", + /* 69 */ "EDQUOT", + /* 70 */ "ESTALE", + /* 71 */ "EREMOTE", + /* 72 */ "EBADRPC", + /* 73 */ "ERPCMISMATCH", + /* 74 */ "EPROGUNAVAIL", + /* 75 */ "EPROGMISMATCH", + /* 76 */ "EPROCUNAVAIL", + /* 77 */ "ENOLCK", + /* 78 */ "ENOSYS", + /* 79 */ "EFTYPE", + /* 80 */ "EAUTH", + /* 81 */ "ENEEDAUTH", + /* 81 */ "ELAST", +}; + +static char *(netbsd_signal_names[]) = { + /* 0 */ 0, + /* 1 */ "SIGHUP", + /* 2 */ "SIGINT", + /* 3 */ "SIGQUIT", + /* 4 */ "SIGILL", + /* 5 */ "SIGTRAP", + /* 6 */ "SIGABRT", + /* 7 */ "SIGEMT", + /* 8 */ "SIGFPE", + /* 9 */ "SIGKILL", + /* 10 */ "SIGBUS", + /* 11 */ "SIGSEGV", + /* 12 */ "SIGSYS", + /* 13 */ "SIGPIPE", + /* 14 */ "SIGALRM", + /* 15 */ "SIGTERM", + /* 16 */ "SIGURG", + /* 17 */ "SIGSTOP", + /* 18 */ "SIGTSTP", + /* 19 */ "SIGCONT", + /* 20 */ "SIGCHLD", + /* 21 */ "SIGTTIN", + /* 22 */ "SIGTTOU", + /* 23 */ "SIGIO", + /* 24 */ "SIGXCPU", + /* 25 */ "SIGXFSZ", + /* 26 */ "SIGVTALRM", + /* 27 */ "SIGPROF", + /* 28 */ "SIGWINCH", + /* 29 */ "SIGINFO", + /* 30 */ "SIGUSR1", + /* 31 */ "SIGUSR2", +}; + +emulation emul_netbsd = { + netbsd_descriptors, + sizeof(netbsd_descriptors) / sizeof(netbsd_descriptors[0]), + netbsd_error_names, + sizeof(netbsd_error_names) / sizeof(netbsd_error_names[0]), + netbsd_signal_names, + sizeof(netbsd_signal_names) / sizeof(netbsd_signal_names[0]), +}; + +#endif /* _EMUL_NETBSD_C_ */ diff --git a/sim/ppc/filter_filename.c b/sim/ppc/filter_filename.c new file mode 100644 index 0000000000..72923b9552 --- /dev/null +++ b/sim/ppc/filter_filename.c @@ -0,0 +1,36 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + +#include "basics.h" + +/* Shorten traces by eliminating the directory component to filenames. */ +extern char * +filter_filename (char *filename) +{ + char *p = filename; + char *last = filename; + int ch; + + while ((ch = *p++) != '\0' && ch != ':') + if (ch == '/') + last = p; + + return last; +} diff --git a/sim/ppc/filter_filename.h b/sim/ppc/filter_filename.h new file mode 100644 index 0000000000..60cc614f09 --- /dev/null +++ b/sim/ppc/filter_filename.h @@ -0,0 +1,27 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + +#ifndef _FILTER_FILENAME_H +#define _FILTER_FILENAME_H + +/* Remove directory part from filename */ +extern char * +filter_filename(char *filename); +#endif diff --git a/sim/ppc/igen.c b/sim/ppc/igen.c new file mode 100644 index 0000000000..78c1494834 --- /dev/null +++ b/sim/ppc/igen.c @@ -0,0 +1,2834 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + 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 +#include +#include +#include + +#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 eg -f 64 to skip 64bit instructions\n"); + printf("-[Ii] -I to dump internal table\n"); + printf("-[Oo] \n"); + printf("-[Kk] \n"); + printf("-[Ss] output schematic.h(S) schematic.c(s)\n"); + printf("-[Dd] output idecode.h(S) idecode.c(s)\n"); + printf("-[Tt] output itable.h(t) itable.c(t)\n"); + printf("-[Cc] output icache.h(S) invalid(s)\n"); + printf("-e Expand (duplicate) semantic functions\n"); + printf("-r Generate a cracking cache of \n"); + printf("-l Supress includsion of CPP line numbering in output files\n"); + } + + while ((ch = getopt(argc, argv, + "ler:f:I:i:O:o:K:k:n:S:s:D:d:T:t:C:")) != -1) { + fprintf(stderr, "\t-%c %s\n", ch, (optarg ? optarg : "")); + switch(ch) { + case 'l': + number_lines = 0; + break; + case 'e': + idecode_expand_semantics = 1; + break; + case 'r': + idecode_cache = a2i(optarg); + break; + case 'f': + { + filter *new_filter = ZALLOC(filter); + new_filter->flag = strdup(optarg); + new_filter->next = filters; + filters = new_filter; + break; + } + case 'I': + case 'i': + ASSERT(opcode_table != NULL); + ASSERT(cache_table != NULL); + instructions = insn_table_load_insns(optarg); + fprintf(stderr, "\texpanding ...\n"); + insn_table_expand_insns(instructions); + fprintf(stderr, "\tcache fields ...\n"); + cache_fields = insn_table_cache_fields(instructions); + if (ch == 'I') { + dump_traverse(instructions); + dump_insn_table(instructions, 0, 1); + } + break; + case 'O': + case 'o': + opcode_table = load_opcode_rules(optarg); + if (ch == 'O') + dump_opcode_rules(opcode_table, 0); + break; + case 'K': + case 'k': + cache_table = load_cache_rules(optarg); + if (ch == 'K') + dump_cache_rules(cache_table, 0); + break; + case 'n': + real_file_name = strdup(optarg); + break; + case 'S': + case 's': + case 'D': + case 'd': + case 'T': + case 't': + case 'C': + { + lf *file = lf_open(optarg, real_file_name, number_lines); + ASSERT(instructions != NULL); + switch (ch) { + case 'S': + gen_semantics_h(instructions, file); + break; + case 's': + gen_semantics_c(instructions, file); + break; + case 'D': + gen_idecode_h(instructions, file); + break; + case 'd': + gen_idecode_c(instructions, file); + break; + case 'T': + gen_itable_h(instructions, file); + break; + case 't': + gen_itable_c(instructions, file); + break; + case 'C': + gen_icache_h(cache_fields, file); + break; + } + lf_close(file); + } + real_file_name = NULL; + break; + default: + error("unknown option\n"); + } + } + return 0; +} diff --git a/sim/ppc/misc.h b/sim/ppc/misc.h new file mode 100644 index 0000000000..0145f620e0 --- /dev/null +++ b/sim/ppc/misc.h @@ -0,0 +1,48 @@ +/* This file is part of the program psim. + + Copyright (C) 1994-1995, Andrew Cagney + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + + +#include "filter_filename.h" + +extern void error +(char *msg, ...); + +#define ASSERT(EXPRESSION) \ +do { \ + if (!(EXPRESSION)) { \ + error("%s:%d: assertion failed - %s\n", \ + filter_filename (__FILE__), __LINE__, #EXPRESSION); \ + } \ +} while (0) + +#define ZALLOC(TYPE) (TYPE*)zalloc(sizeof(TYPE)) + +extern void *zalloc +(long size); + +extern void dumpf +(int indent, char *msg, ...); + +extern int it_is +(const char *flag, + const char *flags); + +extern unsigned a2i +(const char *a); diff --git a/sim/ppc/ppc-instructions b/sim/ppc/ppc-instructions new file mode 100644 index 0000000000..2fa9c6b448 --- /dev/null +++ b/sim/ppc/ppc-instructions @@ -0,0 +1,2414 @@ +# +# This file is part of the program psim. +# +# Copyright (C) 1994-1995, Andrew Cagney +# +# -- +# +# 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