summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.objs8
-rw-r--r--Makefile.target5
-rwxr-xr-xQMP/vm-info2
-rw-r--r--block/blkdebug.c2
-rw-r--r--bsd-user/main.c2
-rw-r--r--check-qjson.c113
-rwxr-xr-xconfigure164
-rw-r--r--cpu-exec.c42
-rwxr-xr-xcreate_config12
-rw-r--r--dyngen-exec.h1
-rw-r--r--exec-all.h1
-rw-r--r--exec.c9
-rw-r--r--hw/9p.h2
-rw-r--r--hw/axis_dev88.c61
-rw-r--r--hw/cris-boot.c97
-rw-r--r--hw/cris-boot.h11
-rw-r--r--hw/eepro100.c1
-rw-r--r--hw/esp.c19
-rw-r--r--hw/etraxfs.c55
-rw-r--r--hw/hpet.c580
-rw-r--r--hw/hpet_emul.h46
-rw-r--r--hw/hw.h11
-rw-r--r--hw/mc146818rtc.c49
-rw-r--r--hw/mc146818rtc.h4
-rw-r--r--hw/mips_jazz.c2
-rw-r--r--hw/mips_malta.c2
-rw-r--r--hw/mips_mipssim.c5
-rw-r--r--hw/mips_r4k.c2
-rw-r--r--hw/multiboot.c9
-rw-r--r--hw/pc.c15
-rw-r--r--hw/petalogix_s3adsp1800_mmu.c4
-rw-r--r--hw/ppc_prep.c2
-rw-r--r--hw/qdev.c1
-rw-r--r--hw/usb-ohci.c4
-rw-r--r--hw/vga-isa-mm.c6
-rw-r--r--hw/virtio-net.c26
-rw-r--r--hw/virtio-serial.h1
-rw-r--r--hw/xenfb.c1
-rw-r--r--hxtool2
-rw-r--r--json-lexer.c114
-rw-r--r--json-parser.c5
-rw-r--r--json-streamer.c8
-rw-r--r--kvm.h1
-rw-r--r--linux-user/main.c7
-rw-r--r--linux-user/syscall.c4
-rw-r--r--migration-exec.c2
-rw-r--r--monitor.c22
-rw-r--r--nbd.h1
-rw-r--r--net.c7
-rw-r--r--net.h1
-rw-r--r--os-posix.c329
-rw-r--r--os-win32.c221
-rw-r--r--pc-bios/optionrom/linuxboot.S8
-rw-r--r--pc-bios/optionrom/optionrom.h32
-rw-r--r--qemu-common.h1
-rw-r--r--qemu-monitor.hx21
-rw-r--r--qemu-options.h41
-rw-r--r--qemu-os-posix.h39
-rw-r--r--qemu-os-win32.h52
-rw-r--r--qjson.c3
-rw-r--r--s390-dis.c166
-rw-r--r--sysemu.h27
-rw-r--r--target-arm/translate.c6
-rw-r--r--target-cris/cpu.h2
-rw-r--r--target-i386/translate.c2
-rw-r--r--target-microblaze/cpu.h7
-rw-r--r--target-mips/cpu.h1
-rw-r--r--target-mips/helper.c21
-rw-r--r--target-mips/helper.h9
-rw-r--r--target-mips/mips-defs.h1
-rw-r--r--target-mips/op_helper.c136
-rw-r--r--target-mips/translate.c3121
-rw-r--r--tcg/arm/tcg-target.c6
-rw-r--r--tcg/hppa/tcg-target.c42
-rw-r--r--tcg/i386/tcg-target.c1190
-rw-r--r--tcg/i386/tcg-target.h61
-rw-r--r--tcg/ia64/tcg-target.c7
-rw-r--r--tcg/mips/tcg-target.c32
-rw-r--r--tcg/ppc/tcg-target.c52
-rw-r--r--tcg/ppc64/tcg-target.c14
-rw-r--r--tcg/s390/tcg-target.c6
-rw-r--r--tcg/s390/tcg-target.h5
-rw-r--r--tcg/sparc/tcg-target.c14
-rw-r--r--tcg/tcg-opc.h293
-rw-r--r--tcg/tcg.c18
-rw-r--r--tcg/tcg.h17
-rw-r--r--tcg/x86_64/tcg-target.c1454
-rw-r--r--tcg/x86_64/tcg-target.h101
-rw-r--r--translate-all.c16
-rw-r--r--vl.c494
-rw-r--r--vnc-encoding-tight.c2
91 files changed, 5976 insertions, 3645 deletions
diff --git a/Makefile.objs b/Makefile.objs
index 54dec26..2bfb6d1 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -49,6 +49,8 @@ common-obj-y += $(net-obj-y)
common-obj-y += $(qobject-obj-y)
common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX))
common-obj-y += readline.o console.o cursor.o async.o qemu-error.o
+common-obj-$(CONFIG_WIN32) += os-win32.o
+common-obj-$(CONFIG_POSIX) += os-posix.o
common-obj-y += tcg-runtime.o host-utils.o
common-obj-y += irq.o ioport.o input.o
@@ -256,8 +258,10 @@ vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
vl.o: QEMU_CFLAGS+=$(SDL_CFLAGS)
-vl.o: qemu-options.h
+vl.o: qemu-options.def
+os-posix.o: qemu-options.def
+os-win32.o: qemu-options.def
-qemu-options.h: $(SRC_PATH)/qemu-options.hx
+qemu-options.def: $(SRC_PATH)/qemu-options.hx
$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@")
diff --git a/Makefile.target b/Makefile.target
index d06c679..478b89d 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -233,7 +233,10 @@ obj-microblaze-y += xilinx_ethlite.o
obj-microblaze-$(CONFIG_FDT) += device_tree.o
# Boards
-obj-cris-y = cris_pic_cpu.o etraxfs.o axis_dev88.o
+obj-cris-y = cris_pic_cpu.o
+obj-cris-y += cris-boot.o
+obj-cris-y += etraxfs.o axis_dev88.o
+obj-cris-y += axis_dev88.o
# IO blocks
obj-cris-y += etraxfs_dma.o
diff --git a/QMP/vm-info b/QMP/vm-info
index b150d82..8ebaeb3 100755
--- a/QMP/vm-info
+++ b/QMP/vm-info
@@ -25,7 +25,7 @@ def main():
qemu = qmp.QEMUMonitorProtocol(argv[1])
qemu.connect()
- for cmd in [ 'version', 'hpet', 'kvm', 'status', 'uuid', 'balloon' ]:
+ for cmd in [ 'version', 'kvm', 'status', 'uuid', 'balloon' ]:
print cmd + ': ' + str(qemu.send('query-' + cmd))
if __name__ == '__main__':
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 8325f75..98fed94 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -26,8 +26,6 @@
#include "block_int.h"
#include "module.h"
-#include <stdbool.h>
-
typedef struct BlkdebugVars {
int state;
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 05cc3d9..aff9f13 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -43,7 +43,7 @@ unsigned long guest_base;
int have_guest_base;
#endif
-static const char *interp_prefix = CONFIG_QEMU_PREFIX;
+static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
extern char **environ;
enum BSDType bsd_type;
diff --git a/check-qjson.c b/check-qjson.c
index 109e777..0b60e45 100644
--- a/check-qjson.c
+++ b/check-qjson.c
@@ -9,7 +9,6 @@
*
*/
#include <check.h>
-#include <stdbool.h>
#include "qstring.h"
#include "qint.h"
@@ -29,6 +28,13 @@ START_TEST(escaped_string)
const char *decoded;
int skip;
} test_cases[] = {
+ { "\"\\b\"", "\b" },
+ { "\"\\f\"", "\f" },
+ { "\"\\n\"", "\n" },
+ { "\"\\r\"", "\r" },
+ { "\"\\t\"", "\t" },
+ { "\"\\/\"", "\\/" },
+ { "\"\\\\\"", "\\" },
{ "\"\\\"\"", "\"" },
{ "\"hello world \\\"embedded string\\\"\"",
"hello world \"embedded string\"" },
@@ -49,11 +55,14 @@ START_TEST(escaped_string)
fail_unless(qobject_type(obj) == QTYPE_QSTRING);
str = qobject_to_qstring(obj);
- fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0);
+ fail_unless(strcmp(qstring_get_str(str), test_cases[i].decoded) == 0,
+ "%s != %s\n", qstring_get_str(str), test_cases[i].decoded);
if (test_cases[i].skip == 0) {
str = qobject_to_json(obj);
- fail_unless(strcmp(qstring_get_str(str), test_cases[i].encoded) == 0);
+ fail_unless(strcmp(qstring_get_str(str),test_cases[i].encoded) == 0,
+ "%s != %s\n", qstring_get_str(str),
+ test_cases[i].encoded);
qobject_decref(obj);
}
@@ -628,11 +637,90 @@ START_TEST(simple_varargs)
}
END_TEST
+START_TEST(empty_input)
+{
+ QObject *obj = qobject_from_json("");
+ fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_string)
+{
+ QObject *obj = qobject_from_json("\"abc");
+ fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_sq_string)
+{
+ QObject *obj = qobject_from_json("'abc");
+ fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_escape)
+{
+ QObject *obj = qobject_from_json("\"abc\\\"");
+ fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_array)
+{
+ QObject *obj = qobject_from_json("[32");
+ fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_array_comma)
+{
+ QObject *obj = qobject_from_json("[32,");
+ fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(invalid_array_comma)
+{
+ QObject *obj = qobject_from_json("[32,}");
+ fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_dict)
+{
+ QObject *obj = qobject_from_json("{'abc':32");
+ fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_dict_comma)
+{
+ QObject *obj = qobject_from_json("{'abc':32,");
+ fail_unless(obj == NULL);
+}
+END_TEST
+
+#if 0
+START_TEST(invalid_dict_comma)
+{
+ QObject *obj = qobject_from_json("{'abc':32,}");
+ fail_unless(obj == NULL);
+}
+END_TEST
+
+START_TEST(unterminated_literal)
+{
+ QObject *obj = qobject_from_json("nul");
+ fail_unless(obj == NULL);
+}
+END_TEST
+#endif
+
static Suite *qjson_suite(void)
{
Suite *suite;
TCase *string_literals, *number_literals, *keyword_literals;
- TCase *dicts, *lists, *whitespace, *varargs;
+ TCase *dicts, *lists, *whitespace, *varargs, *errors;
string_literals = tcase_create("String Literals");
tcase_add_test(string_literals, simple_string);
@@ -658,6 +746,22 @@ static Suite *qjson_suite(void)
varargs = tcase_create("Varargs");
tcase_add_test(varargs, simple_varargs);
+ errors = tcase_create("Invalid JSON");
+ tcase_add_test(errors, empty_input);
+ tcase_add_test(errors, unterminated_string);
+ tcase_add_test(errors, unterminated_escape);
+ tcase_add_test(errors, unterminated_sq_string);
+ tcase_add_test(errors, unterminated_array);
+ tcase_add_test(errors, unterminated_array_comma);
+ tcase_add_test(errors, invalid_array_comma);
+ tcase_add_test(errors, unterminated_dict);
+ tcase_add_test(errors, unterminated_dict_comma);
+#if 0
+ /* FIXME: this print parse error messages on stderr. */
+ tcase_add_test(errors, invalid_dict_comma);
+ tcase_add_test(errors, unterminated_literal);
+#endif
+
suite = suite_create("QJSON test-suite");
suite_add_tcase(suite, string_literals);
suite_add_tcase(suite, number_literals);
@@ -666,6 +770,7 @@ static Suite *qjson_suite(void)
suite_add_tcase(suite, lists);
suite_add_tcase(suite, whitespace);
suite_add_tcase(suite, varargs);
+ suite_add_tcase(suite, errors);
return suite;
}
diff --git a/configure b/configure
index 653c8d2..c0d8aa5 100755
--- a/configure
+++ b/configure
@@ -15,7 +15,7 @@ TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe"
-trap "rm -f $TMPC $TMPO $TMPE ; exit" 0 2 3 15
+trap "rm -f $TMPC $TMPO $TMPE ; exit" EXIT INT QUIT TERM
compile_object() {
$cc $QEMU_CFLAGS -c -o $TMPO $TMPC > /dev/null 2> /dev/null
@@ -65,10 +65,8 @@ path_of() {
# default parameters
cpu=""
-prefix=""
interp_prefix="/usr/gnemul/qemu-%M"
static="no"
-sysconfdir=""
sparc_cpu=""
cross_prefix=""
cc="gcc"
@@ -195,6 +193,12 @@ elif check_define __mips__ ; then
cpu="mips"
elif check_define __ia64__ ; then
cpu="ia64"
+elif check_define __s390__ ; then
+ if check_define __s390x__ ; then
+ cpu="s390x"
+ else
+ cpu="s390"
+ fi
else
cpu=`uname -m`
fi
@@ -232,7 +236,8 @@ case "$cpu" in
cpu="sparc"
;;
*)
- cpu="unknown"
+ echo "Unsupported CPU = $cpu"
+ exit 1
;;
esac
@@ -275,6 +280,13 @@ strip_opt="yes"
bigendian="no"
mingw32="no"
EXESUF=""
+prefix="/usr/local"
+mandir="\${prefix}/share/man"
+datadir="\${prefix}/share/qemu"
+docdir="\${prefix}/share/doc/qemu"
+bindir="\${prefix}/bin"
+sysconfdir="\${prefix}/etc"
+confsuffix="/qemu"
slirp="yes"
fmod_lib=""
fmod_inc=""
@@ -449,6 +461,13 @@ if test "$mingw32" = "yes" ; then
# enable C99/POSIX format strings (needs mingw32-runtime 3.15 or later)
QEMU_CFLAGS="-D__USE_MINGW_ANSI_STDIO=1 $QEMU_CFLAGS"
LIBS="-lwinmm -lws2_32 -liphlpapi $LIBS"
+ prefix="c:/Program Files/Qemu"
+ mandir="\${prefix}"
+ datadir="\${prefix}"
+ docdir="\${prefix}"
+ bindir="\${prefix}"
+ sysconfdir="\${prefix}"
+ confsuffix=""
fi
# find source path
@@ -500,6 +519,14 @@ for opt do
static="yes"
LDFLAGS="-static $LDFLAGS"
;;
+ --mandir=*) mandir="$optarg"
+ ;;
+ --bindir=*) bindir="$optarg"
+ ;;
+ --datadir=*) datadir="$optarg"
+ ;;
+ --docdir=*) docdir="$optarg"
+ ;;
--sysconfdir=*) sysconfdir="$optarg"
;;
--disable-sdl) sdl="no"
@@ -660,6 +687,8 @@ for opt do
;;
--enable-vhost-net) vhost_net="yes"
;;
+ --*dir)
+ ;;
*) echo "ERROR: unknown option $opt"; show_help="yes"
;;
esac
@@ -697,7 +726,12 @@ case "$cpu" in
fi
;;
s390)
- QEMU_CFLAGS="-march=z900 $QEMU_CFLAGS"
+ QEMU_CFLAGS="-m31 -march=z990 $QEMU_CFLAGS"
+ LDFLAGS="-m31 $LDFLAGS"
+ ;;
+ s390x)
+ QEMU_CFLAGS="-m64 -march=z990 $QEMU_CFLAGS"
+ LDFLAGS="-m64 $LDFLAGS"
;;
i386)
QEMU_CFLAGS="-m32 $QEMU_CFLAGS"
@@ -747,13 +781,18 @@ echo "Advanced options (experts only):"
echo " --source-path=PATH path of source code [$source_path]"
echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]"
echo " --cc=CC use C compiler CC [$cc]"
-echo " --host-cc=CC use C compiler CC [$host_cc] for dyngen etc."
+echo " --host-cc=CC use C compiler CC [$host_cc] for code run at"
+echo " build time"
echo " --extra-cflags=CFLAGS append extra C compiler flags QEMU_CFLAGS"
echo " --extra-ldflags=LDFLAGS append extra linker flags LDFLAGS"
echo " --make=MAKE use specified make [$make]"
echo " --install=INSTALL use specified install [$install]"
echo " --static enable static build [$static]"
-echo " --sysconfdir=PATH install config in PATH"
+echo " --mandir=PATH install man pages in PATH"
+echo " --datadir=PATH install firmware in PATH"
+echo " --docdir=PATH install documentation in PATH"
+echo " --bindir=PATH install binaries in PATH"
+echo " --sysconfdir=PATH install config in PATH/qemu"
echo " --enable-debug-tcg enable TCG debugging"
echo " --disable-debug-tcg disable TCG debugging (default)"
echo " --enable-debug enable common debug build options"
@@ -927,6 +966,13 @@ if test -z "$target_list" ; then
echo "No targets enabled"
exit 1
fi
+# see if system emulation was really requested
+case " $target_list " in
+ *"-softmmu "*) softmmu=yes
+ ;;
+ *) softmmu=no
+ ;;
+esac
feature_not_found() {
feature=$1
@@ -1546,7 +1592,7 @@ EOF
fi
else
if test "$vhost_net" = "yes" ; then
- echo -e "NOTE: vhost-net feature requires KVM (--enable-kvm)."
+ echo "NOTE: vhost-net feature requires KVM (--enable-kvm)."
feature_not_found "vhost-net"
fi
vhost_net=no
@@ -1954,36 +2000,35 @@ if test "$solaris" = "no" ; then
fi
fi
-if test "$mingw32" = "yes" ; then
- if test -z "$prefix" ; then
- prefix="c:/Program Files/Qemu"
- fi
- mansuffix=""
- datasuffix=""
- confsuffix=""
- docsuffix=""
- binsuffix=""
- if test -z "$sysconfdir" ; then
- sysconfdir="${prefix}"
- fi
-else
- if test -z "$prefix" ; then
- prefix="/usr/local"
- fi
- mansuffix="/share/man"
- datasuffix="/share/qemu"
- docsuffix="/share/doc/qemu"
- binsuffix="/bin"
- if test -z "$sysconfdir" ; then
- sysconfdir="${prefix}/etc"
+confdir=$sysconfdir$confsuffix
+
+tools=
+if test "$softmmu" = yes ; then
+ tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
+ if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
+ tools="qemu-nbd\$(EXESUF) $tools"
+ if [ "$check_utests" = "yes" ]; then
+ tools="check-qint check-qstring check-qdict check-qlist $tools"
+ tools="check-qfloat check-qjson $tools"
+ fi
fi
fi
+# Mac OS X ships with a broken assembler
+roms=
+if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) -a \
+ "$targetos" != "Darwin" -a "$targetos" != "SunOS" -a \
+ "$softmmu" = yes ; then
+ roms="optionrom"
+fi
+
+
echo "Install prefix $prefix"
-echo "BIOS directory $prefix$datasuffix"
-echo "binary directory $prefix$binsuffix"
+echo "BIOS directory `eval echo $datadir`"
+echo "binary directory `eval echo $bindir`"
+echo "config directory `eval echo $sysconfdir`"
if test "$mingw32" = "no" ; then
-echo "Manual directory $prefix$mansuffix"
+echo "Manual directory `eval echo $mandir`"
echo "ELF interp prefix $interp_prefix"
fi
echo "Source path $source_path"
@@ -2054,12 +2099,13 @@ printf "# Configured with:" >> $config_host_mak
printf " '%s'" "$0" "$@" >> $config_host_mak
echo >> $config_host_mak
-echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
-if test "$mingw32" = "yes" ; then
- echo "CONFIG_QEMU_CONFDIR=\"$sysconfdir\"" >> $config_host_mak
-else
- echo "CONFIG_QEMU_CONFDIR=\"${sysconfdir}/qemu\"" >> $config_host_mak
-fi
+echo "prefix=$prefix" >> $config_host_mak
+echo "bindir=$bindir" >> $config_host_mak
+echo "mandir=$mandir" >> $config_host_mak
+echo "datadir=$datadir" >> $config_host_mak
+echo "sysconfdir=$sysconfdir" >> $config_host_mak
+echo "docdir=$docdir" >> $config_host_mak
+echo "confdir=$confdir" >> $config_host_mak
case "$cpu" in
i386|x86_64|alpha|cris|hppa|ia64|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64)
@@ -2068,10 +2114,6 @@ case "$cpu" in
armv4b|armv4l)
ARCH=arm
;;
- *)
- echo "Unsupported CPU = $cpu"
- exit 1
- ;;
esac
echo "ARCH=$ARCH" >> $config_host_mak
if test "$debug_tcg" = "yes" ; then
@@ -2284,34 +2326,8 @@ bsd)
;;
esac
-tools=
-if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then
- tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools"
- if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then
- tools="qemu-nbd\$(EXESUF) $tools"
- if [ "$check_utests" = "yes" ]; then
- tools="check-qint check-qstring check-qdict check-qlist $tools"
- tools="check-qfloat check-qjson $tools"
- fi
- fi
-fi
echo "TOOLS=$tools" >> $config_host_mak
-
-# Mac OS X ships with a broken assembler
-roms=
-if test \( "$cpu" = "i386" -o "$cpu" = "x86_64" \) -a \
- "$targetos" != "Darwin" -a "$targetos" != "SunOS" -a \
- `expr "$target_list" : ".*softmmu.*"` != 0 ; then
- roms="optionrom"
-fi
echo "ROMS=$roms" >> $config_host_mak
-
-echo "prefix=$prefix" >> $config_host_mak
-echo "bindir=\${prefix}$binsuffix" >> $config_host_mak
-echo "mandir=\${prefix}$mansuffix" >> $config_host_mak
-echo "datadir=\${prefix}$datasuffix" >> $config_host_mak
-echo "sysconfdir=$sysconfdir" >> $config_host_mak
-echo "docdir=\${prefix}$docsuffix" >> $config_host_mak
echo "MAKE=$make" >> $config_host_mak
echo "INSTALL=$install" >> $config_host_mak
echo "INSTALL_DIR=$install -d -m0755 -p" >> $config_host_mak
@@ -2355,6 +2371,9 @@ for d in libdis libdis-user; do
ln -s $source_path/Makefile.dis $d/Makefile
echo > $d/config.mak
done
+if test "$static" = "no" -a "$user_pie" = "yes" ; then
+ echo "QEMU_CFLAGS+=-fpie" > libdis-user/config.mak
+fi
for target in $target_list; do
target_dir="$target"
@@ -2426,7 +2445,7 @@ echo "# Automatically generated by configure - do not modify" > $config_target_m
bflt="no"
target_nptl="no"
interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_arch2/g"`
-echo "CONFIG_QEMU_PREFIX=\"$interp_prefix1\"" >> $config_target_mak
+echo "CONFIG_QEMU_INTERP_PREFIX=\"$interp_prefix1\"" >> $config_target_mak
gdb_xml_files=""
TARGET_ARCH="$target_arch2"
@@ -2635,6 +2654,8 @@ if test "$ARCH" = "sparc64" ; then
cflags="-I\$(SRC_PATH)/tcg/sparc $cflags"
elif test "$ARCH" = "s390x" ; then
cflags="-I\$(SRC_PATH)/tcg/s390 $cflags"
+elif test "$ARCH" = "x86_64" ; then
+ cflags="-I\$(SRC_PATH)/tcg/i386 $cflags"
else
cflags="-I\$(SRC_PATH)/tcg/\$(ARCH) $cflags"
fi
@@ -2753,6 +2774,9 @@ if test "$target_linux_user" = "yes" -o "$target_bsd_user" = "yes" ; then
# -static is used to avoid g1/g3 usage by the dynamic linker
ldflags="$linker_script -static $ldflags"
;;
+ alpha | s390x)
+ # The default placement of the application is fine.
+ ;;
*)
ldflags="$linker_script $ldflags"
;;
diff --git a/cpu-exec.c b/cpu-exec.c
index c776605..026980a 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -1156,11 +1156,47 @@ int cpu_signal_handler(int host_signum, void *pinfo,
siginfo_t *info = pinfo;
struct ucontext *uc = puc;
unsigned long pc;
- int is_write;
+ uint16_t *pinsn;
+ int is_write = 0;
pc = uc->uc_mcontext.psw.addr;
- /* XXX: compute is_write */
- is_write = 0;
+
+ /* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
+ of the normal 2 arguments. The 3rd argument contains the "int_code"
+ from the hardware which does in fact contain the is_write value.
+ The rt signal handler, as far as I can tell, does not give this value
+ at all. Not that we could get to it from here even if it were. */
+ /* ??? This is not even close to complete, since it ignores all
+ of the read-modify-write instructions. */
+ pinsn = (uint16_t *)pc;
+ switch (pinsn[0] >> 8) {
+ case 0x50: /* ST */
+ case 0x42: /* STC */
+ case 0x40: /* STH */
+ is_write = 1;
+ break;
+ case 0xc4: /* RIL format insns */
+ switch (pinsn[0] & 0xf) {
+ case 0xf: /* STRL */
+ case 0xb: /* STGRL */
+ case 0x7: /* STHRL */
+ is_write = 1;
+ }
+ break;
+ case 0xe3: /* RXY format insns */
+ switch (pinsn[2] & 0xff) {
+ case 0x50: /* STY */
+ case 0x24: /* STG */
+ case 0x72: /* STCY */
+ case 0x70: /* STHY */
+ case 0x8e: /* STPQ */
+ case 0x3f: /* STRVH */
+ case 0x3e: /* STRV */
+ case 0x2f: /* STRVG */
+ is_write = 1;
+ }
+ break;
+ }
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write, &uc->uc_sigmask, puc);
}
diff --git a/create_config b/create_config
index 2f052ae..0098e68 100755
--- a/create_config
+++ b/create_config
@@ -13,10 +13,14 @@ case $line in
pkgversion=${line#*=}
echo "#define QEMU_PKGVERSION \"$pkgversion\""
;;
- ARCH=*) # configuration
- arch=${line#*=}
- arch_name=`echo $arch | tr '[:lower:]' '[:upper:]'`
- echo "#define HOST_$arch_name 1"
+ prefix=* | [a-z]*dir=*) # directory configuration
+ name=${line%=*}
+ value=${line#*=}
+ define_name=`echo $name | tr '[:lower:]' '[:upper:]'`
+ eval "define_value=\"$value\""
+ echo "#define CONFIG_QEMU_$define_name \"$define_value\""
+ # save for the next definitions
+ eval "$name=\$define_value"
;;
CONFIG_AUDIO_DRIVERS=*)
drivers=${line#*=}
diff --git a/dyngen-exec.h b/dyngen-exec.h
index 0700a2d..5bfef3f 100644
--- a/dyngen-exec.h
+++ b/dyngen-exec.h
@@ -31,6 +31,7 @@
host headers do not allow that. */
#include <stddef.h>
#include <stdint.h>
+#include <stdbool.h>
#ifdef __OpenBSD__
#include <sys/types.h>
diff --git a/exec-all.h b/exec-all.h
index 4565dd0..a775582 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -80,7 +80,6 @@ void gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
void gen_pc_load(CPUState *env, struct TranslationBlock *tb,
unsigned long searched_pc, int pc_pos, void *puc);
-unsigned long code_gen_max_block_size(void);
void cpu_gen_init(void);
int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
int *gen_code_size_ptr);
diff --git a/exec.c b/exec.c
index bb3dcad..4273797 100644
--- a/exec.c
+++ b/exec.c
@@ -519,6 +519,13 @@ static void code_gen_alloc(unsigned long tb_size)
start = (void *) 0x01000000UL;
if (code_gen_buffer_size > 16 * 1024 * 1024)
code_gen_buffer_size = 16 * 1024 * 1024;
+#elif defined(__s390x__)
+ /* Map the buffer so that we can use direct calls and branches. */
+ /* We have a +- 4GB range on the branches; leave some slop. */
+ if (code_gen_buffer_size > (3ul * 1024 * 1024 * 1024)) {
+ code_gen_buffer_size = 3ul * 1024 * 1024 * 1024;
+ }
+ start = (void *)0x90000000UL;
#endif
code_gen_buffer = mmap(start, code_gen_buffer_size,
PROT_WRITE | PROT_READ | PROT_EXEC,
@@ -557,7 +564,7 @@ static void code_gen_alloc(unsigned long tb_size)
#endif /* !USE_STATIC_CODE_GEN_BUFFER */
map_exec(code_gen_prologue, sizeof(code_gen_prologue));
code_gen_buffer_max_size = code_gen_buffer_size -
- code_gen_max_block_size();
+ (TCG_MAX_OP_SIZE * OPC_MAX_SIZE);
code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
}
diff --git a/hw/9p.h b/hw/9p.h
index 5fdd770..d9951d6 100644
--- a/hw/9p.h
+++ b/hw/9p.h
@@ -14,8 +14,6 @@
#ifndef QEMU_9P_H
#define QEMU_9P_H
-#include <stdbool.h>
-
typedef struct V9fsConf
{
/* tag name for the device */
diff --git a/hw/axis_dev88.c b/hw/axis_dev88.c
index 7d59c96..3ae4105 100644
--- a/hw/axis_dev88.c
+++ b/hw/axis_dev88.c
@@ -30,6 +30,7 @@
#include "etraxfs.h"
#include "loader.h"
#include "elf.h"
+#include "cris-boot.h"
#define D(x)
#define DNAND(x)
@@ -240,28 +241,7 @@ static CPUWriteMemoryFunc * const gpio_write[] = {
#define INTMEM_SIZE (128 * 1024)
-static struct {
- uint32_t bootstrap_pc;
- uint32_t regs[16];
-} loadargs;
-
-static void main_cpu_reset(void *opaque)
-{
- int i;
-
- CPUState *env = opaque;
- cpu_reset(env);
-
- env->pc = loadargs.bootstrap_pc;
- for (i = 0; i < 16; i++) {
- env->regs[i] = loadargs.regs[i];
- }
-}
-
-static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
-{
- return addr - 0x80000000LL;
-}
+static struct cris_load_info li;
static
void axisdev88_init (ram_addr_t ram_size,
@@ -275,7 +255,6 @@ void axisdev88_init (ram_addr_t ram_size,
qemu_irq irq[30], nmi[2], *cpu_irq;
void *etraxfs_dmac;
struct etraxfs_dma_client *eth[2] = {NULL, NULL};
- int kernel_size;
int i;
int nand_regs;
int gpio_regs;
@@ -287,7 +266,6 @@ void axisdev88_init (ram_addr_t ram_size,
cpu_model = "crisv32";
}
env = cpu_init(cpu_model);
- qemu_register_reset(main_cpu_reset, env);
/* allocate RAM */
phys_ram = qemu_ram_alloc(ram_size);
@@ -353,35 +331,14 @@ void axisdev88_init (ram_addr_t ram_size,
irq[0x14 + i]);
}
- if (kernel_filename) {
- uint64_t entry, high;
- int kcmdline_len;
-
- /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis
- devboard SDK. */
- kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
- &entry, NULL, &high, 0, ELF_MACHINE, 0);
- loadargs.bootstrap_pc = entry;
- if (kernel_size < 0) {
- /* Takes a kimage from the axis devboard SDK. */
- kernel_size = load_image_targphys(kernel_filename, 0x40004000,
- ram_size);
- loadargs.bootstrap_pc = 0x40004000;
- loadargs.regs[9] = 0x40004000 + kernel_size;
- }
- loadargs.regs[8] = 0x56902387; /* RAM init magic. */
-
- if (kernel_cmdline && (kcmdline_len = strlen(kernel_cmdline))) {
- if (kcmdline_len > 256) {
- fprintf(stderr, "Too long CRIS kernel cmdline (max 256)\n");
- exit(1);
- }
- /* Let the kernel know we are modifying the cmdline. */
- loadargs.regs[10] = 0x87109563;
- loadargs.regs[11] = 0x40000000;
- pstrcpy_targphys("cmdline", loadargs.regs[11], 256, kernel_cmdline);
- }
+ if (!kernel_filename) {
+ fprintf(stderr, "Kernel image must be specified\n");
+ exit(1);
}
+
+ li.image_filename = kernel_filename;
+ li.cmdline = kernel_cmdline;
+ cris_load_image(env, &li);
}
static QEMUMachine axisdev88_machine = {
diff --git a/hw/cris-boot.c b/hw/cris-boot.c
new file mode 100644
index 0000000..2ef17f6
--- /dev/null
+++ b/hw/cris-boot.c
@@ -0,0 +1,97 @@
+/*
+ * CRIS image loading.
+ *
+ * Copyright (c) 2010 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw.h"
+#include "sysemu.h"
+#include "loader.h"
+#include "elf.h"
+#include "cris-boot.h"
+
+static void main_cpu_reset(void *opaque)
+{
+ CPUState *env = opaque;
+ struct cris_load_info *li;
+
+ li = env->load_info;
+
+ cpu_reset(env);
+
+ if (!li) {
+ /* nothing more to do. */
+ return;
+ }
+
+ env->pc = li->entry;
+
+ if (li->image_filename) {
+ env->regs[8] = 0x56902387; /* RAM boot magic. */
+ env->regs[9] = 0x40004000 + li->image_size;
+ }
+
+ if (li->cmdline) {
+ /* Let the kernel know we are modifying the cmdline. */
+ env->regs[10] = 0x87109563;
+ env->regs[11] = 0x40000000;
+ }
+}
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+ return addr - 0x80000000LL;
+}
+
+void cris_load_image(CPUState *env, struct cris_load_info *li)
+{
+ uint64_t entry, high;
+ int kcmdline_len;
+ int image_size;
+
+ env->load_info = li;
+ /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis
+ devboard SDK. */
+ image_size = load_elf(li->image_filename, translate_kernel_address, NULL,
+ &entry, NULL, &high, 0, ELF_MACHINE, 0);
+ li->entry = entry;
+ if (image_size < 0) {
+ /* Takes a kimage from the axis devboard SDK. */
+ image_size = load_image_targphys(li->image_filename, 0x40004000,
+ ram_size);
+ li->entry = 0x40004000;
+ }
+
+ if (image_size < 0) {
+ fprintf(stderr, "qemu: could not load kernel '%s'\n",
+ li->image_filename);
+ exit(1);
+ }
+
+ if (li->cmdline && (kcmdline_len = strlen(li->cmdline))) {
+ if (kcmdline_len > 256) {
+ fprintf(stderr, "Too long CRIS kernel cmdline (max 256)\n");
+ exit(1);
+ }
+ pstrcpy_targphys("cmdline", 0x40000000, 256, li->cmdline);
+ }
+ qemu_register_reset(main_cpu_reset, env);
+}
diff --git a/hw/cris-boot.h b/hw/cris-boot.h
new file mode 100644
index 0000000..e9caf8d
--- /dev/null
+++ b/hw/cris-boot.h
@@ -0,0 +1,11 @@
+
+struct cris_load_info
+{
+ const char *image_filename;
+ const char *cmdline;
+ int image_size;
+
+ target_phys_addr_t entry;
+};
+
+void cris_load_image(CPUState *env, struct cris_load_info *li);
diff --git a/hw/eepro100.c b/hw/eepro100.c
index a74d834..97afa2c 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -41,7 +41,6 @@
* * Wake-on-LAN is not implemented.
*/
-#include <stdbool.h> /* bool */
#include <stddef.h> /* offsetof */
#include "hw.h"
#include "pci.h"
diff --git a/hw/esp.c b/hw/esp.c
index 0a8cf6e..7740879 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -419,7 +419,7 @@ static void handle_ti(ESPState *s)
}
}
-static void esp_reset(DeviceState *d)
+static void esp_hard_reset(DeviceState *d)
{
ESPState *s = container_of(d, ESPState, busdev.qdev);
@@ -435,10 +435,19 @@ static void esp_reset(DeviceState *d)
s->rregs[ESP_CFG1] = 7;
}
+static void esp_soft_reset(DeviceState *d)
+{
+ ESPState *s = container_of(d, ESPState, busdev.qdev);
+
+ qemu_irq_lower(s->irq);
+ esp_hard_reset(d);
+}
+
static void parent_esp_reset(void *opaque, int irq, int level)
{
- if (level)
- esp_reset(opaque);
+ if (level) {
+ esp_soft_reset(opaque);
+ }
}
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
@@ -528,7 +537,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
break;
case CMD_RESET:
DPRINTF("Chip reset (%2.2x)\n", val);
- esp_reset(&s->busdev.qdev);
+ esp_soft_reset(&s->busdev.qdev);
break;
case CMD_BUSRESET:
DPRINTF("Bus reset (%2.2x)\n", val);
@@ -679,7 +688,7 @@ static SysBusDeviceInfo esp_info = {
.qdev.name = "esp",
.qdev.size = sizeof(ESPState),
.qdev.vmsd = &vmstate_esp,
- .qdev.reset = esp_reset,
+ .qdev.reset = esp_hard_reset,
.qdev.props = (Property[]) {
{.name = NULL}
}
diff --git a/hw/etraxfs.c b/hw/etraxfs.c
index b88d00a..01bf929 100644
--- a/hw/etraxfs.c
+++ b/hw/etraxfs.c
@@ -30,23 +30,17 @@
#include "etraxfs.h"
#include "loader.h"
#include "elf.h"
+#include "cris-boot.h"
#define FLASH_SIZE 0x2000000
#define INTMEM_SIZE (128 * 1024)
-static uint32_t bootstrap_pc;
+static struct cris_load_info li;
-static void main_cpu_reset(void *opaque)
+static void flash_cpu_reset(void *opaque)
{
CPUState *env = opaque;
cpu_reset(env);
-
- env->pc = bootstrap_pc;
-}
-
-static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
-{
- return addr - 0x80000000LL;
}
static
@@ -61,7 +55,6 @@ void bareetraxfs_init (ram_addr_t ram_size,
qemu_irq irq[30], nmi[2], *cpu_irq;
void *etraxfs_dmac;
struct etraxfs_dma_client *eth[2] = {NULL, NULL};
- int kernel_size;
DriveInfo *dinfo;
int i;
ram_addr_t phys_ram;
@@ -73,7 +66,6 @@ void bareetraxfs_init (ram_addr_t ram_size,
cpu_model = "crisv32";
}
env = cpu_init(cpu_model);
- qemu_register_reset(main_cpu_reset, env);
/* allocate RAM */
phys_ram = qemu_ram_alloc(ram_size);
@@ -137,38 +129,19 @@ void bareetraxfs_init (ram_addr_t ram_size,
}
if (kernel_filename) {
- uint64_t entry, high;
- int kcmdline_len;
-
- /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis
- devboard SDK. */
- kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
- &entry, NULL, &high, 0, ELF_MACHINE, 0);
- bootstrap_pc = entry;
- if (kernel_size < 0) {
- /* Takes a kimage from the axis devboard SDK. */
- kernel_size = load_image_targphys(kernel_filename, 0x40004000,
- ram_size);
- bootstrap_pc = 0x40004000;
- env->regs[9] = 0x40004000 + kernel_size;
+ li.image_filename = kernel_filename;
+ li.cmdline = kernel_cmdline;
+ cris_load_image(env, &li);
+ } else {
+ if (!dinfo) {
+ fprintf(stderr,
+ "Provide a kernel image or a flash image to boot from.\n");
+ exit(1);
}
- env->regs[8] = 0x56902387; /* RAM init magic. */
-
- if (kernel_cmdline && (kcmdline_len = strlen(kernel_cmdline))) {
- if (kcmdline_len > 256) {
- fprintf(stderr, "Too long CRIS kernel cmdline (max 256)\n");
- exit(1);
- }
- /* Let the kernel know we are modifying the cmdline. */
- env->regs[10] = 0x87109563;
- env->regs[11] = 0x40000000;
- pstrcpy_targphys("cmdline", env->regs[11], 256, kernel_cmdline);
- }
- }
- env->pc = bootstrap_pc;
- printf ("pc =%x\n", env->pc);
- printf ("ram size =%ld\n", ram_size);
+ /* Nothing more to do for flash images, those boot from addr 0. */
+ qemu_register_reset(flash_cpu_reset, env);
+ }
}
static QEMUMachine bareetraxfs_machine = {
diff --git a/hw/hpet.c b/hw/hpet.c
index 8729fb2..93fc399 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -29,6 +29,8 @@
#include "console.h"
#include "qemu-timer.h"
#include "hpet_emul.h"
+#include "sysbus.h"
+#include "mc146818rtc.h"
//#define HPET_DEBUG
#ifdef HPET_DEBUG
@@ -37,26 +39,58 @@
#define DPRINTF(...)
#endif
-static HPETState *hpet_statep;
-
-uint32_t hpet_in_legacy_mode(void)
+#define HPET_MSI_SUPPORT 0
+
+struct HPETState;
+typedef struct HPETTimer { /* timers */
+ uint8_t tn; /*timer number*/
+ QEMUTimer *qemu_timer;
+ struct HPETState *state;
+ /* Memory-mapped, software visible timer registers */
+ uint64_t config; /* configuration/cap */
+ uint64_t cmp; /* comparator */
+ uint64_t fsb; /* FSB route */
+ /* Hidden register state */
+ uint64_t period; /* Last value written to comparator */
+ uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit
+ * mode. Next pop will be actual timer expiration.
+ */
+} HPETTimer;
+
+typedef struct HPETState {
+ SysBusDevice busdev;
+ uint64_t hpet_offset;
+ qemu_irq irqs[HPET_NUM_IRQ_ROUTES];
+ uint32_t flags;
+ uint8_t rtc_irq_level;
+ uint8_t num_timers;
+ HPETTimer timer[HPET_MAX_TIMERS];
+
+ /* Memory-mapped, software visible registers */
+ uint64_t capability; /* capabilities */
+ uint64_t config; /* configuration */
+ uint64_t isr; /* interrupt status reg */
+ uint64_t hpet_counter; /* main counter */
+} HPETState;
+
+static uint32_t hpet_in_legacy_mode(HPETState *s)
{
- if (hpet_statep)
- return hpet_statep->config & HPET_CFG_LEGACY;
- else
- return 0;
+ return s->config & HPET_CFG_LEGACY;
}
static uint32_t timer_int_route(struct HPETTimer *timer)
{
- uint32_t route;
- route = (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
- return route;
+ return (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
}
-static uint32_t hpet_enabled(void)
+static uint32_t timer_fsb_route(HPETTimer *t)
{
- return hpet_statep->config & HPET_CFG_ENABLE;
+ return t->config & HPET_TN_FSB_ENABLE;
+}
+
+static uint32_t hpet_enabled(HPETState *s)
+{
+ return s->config & HPET_CFG_ENABLE;
}
static uint32_t timer_is_periodic(HPETTimer *t)
@@ -106,11 +140,9 @@ static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask)
return ((old & mask) && !(new & mask));
}
-static uint64_t hpet_get_ticks(void)
+static uint64_t hpet_get_ticks(HPETState *s)
{
- uint64_t ticks;
- ticks = ns_to_ticks(qemu_get_clock(vm_clock) + hpet_statep->hpet_offset);
- return ticks;
+ return ns_to_ticks(qemu_get_clock(vm_clock) + s->hpet_offset);
}
/*
@@ -121,12 +153,14 @@ static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current)
if (t->config & HPET_TN_32BIT) {
uint32_t diff, cmp;
+
cmp = (uint32_t)t->cmp;
diff = cmp - (uint32_t)current;
diff = (int32_t)diff > 0 ? diff : (uint32_t)0;
return (uint64_t)diff;
} else {
uint64_t diff, cmp;
+
cmp = t->cmp;
diff = cmp - current;
diff = (int64_t)diff > 0 ? diff : (uint64_t)0;
@@ -134,34 +168,54 @@ static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current)
}
}
-static void update_irq(struct HPETTimer *timer)
+static void update_irq(struct HPETTimer *timer, int set)
{
- qemu_irq irq;
+ uint64_t mask;
+ HPETState *s;
int route;
- if (timer->tn <= 1 && hpet_in_legacy_mode()) {
+ if (timer->tn <= 1 && hpet_in_legacy_mode(timer->state)) {
/* if LegacyReplacementRoute bit is set, HPET specification requires
* timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
* timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC.
*/
- if (timer->tn == 0) {
- irq=timer->state->irqs[0];
- } else
- irq=timer->state->irqs[8];
+ route = (timer->tn == 0) ? 0 : RTC_ISA_IRQ;
} else {
- route=timer_int_route(timer);
- irq=timer->state->irqs[route];
+ route = timer_int_route(timer);
}
- if (timer_enabled(timer) && hpet_enabled()) {
- qemu_irq_pulse(irq);
+ s = timer->state;
+ mask = 1 << timer->tn;
+ if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) {
+ s->isr &= ~mask;
+ if (!timer_fsb_route(timer)) {
+ qemu_irq_lower(s->irqs[route]);
+ }
+ } else if (timer_fsb_route(timer)) {
+ stl_phys(timer->fsb >> 32, timer->fsb & 0xffffffff);
+ } else if (timer->config & HPET_TN_TYPE_LEVEL) {
+ s->isr |= mask;
+ qemu_irq_raise(s->irqs[route]);
+ } else {
+ s->isr &= ~mask;
+ qemu_irq_pulse(s->irqs[route]);
}
}
static void hpet_pre_save(void *opaque)
{
HPETState *s = opaque;
+
/* save current counter value */
- s->hpet_counter = hpet_get_ticks();
+ s->hpet_counter = hpet_get_ticks(s);
+}
+
+static int hpet_pre_load(void *opaque)
+{
+ HPETState *s = opaque;
+
+ /* version 1 only supports 3, later versions will load the actual value */
+ s->num_timers = HPET_MIN_TIMERS;
+ return 0;
}
static int hpet_post_load(void *opaque, int version_id)
@@ -170,6 +224,16 @@ static int hpet_post_load(void *opaque, int version_id)
/* Recalculate the offset between the main counter and guest time */
s->hpet_offset = ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock);
+
+ /* Push number of timers into capability returned via HPET_ID */
+ s->capability &= ~HPET_ID_NUM_TIM_MASK;
+ s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
+
+ /* Derive HPET_MSI_SUPPORT from the capability of the first timer. */
+ s->flags &= ~(1 << HPET_MSI_SUPPORT);
+ if (s->timer[0].config & HPET_TN_FSB_CAP) {
+ s->flags |= 1 << HPET_MSI_SUPPORT;
+ }
return 0;
}
@@ -192,17 +256,19 @@ static const VMStateDescription vmstate_hpet_timer = {
static const VMStateDescription vmstate_hpet = {
.name = "hpet",
- .version_id = 1,
+ .version_id = 2,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.pre_save = hpet_pre_save,
+ .pre_load = hpet_pre_load,
.post_load = hpet_post_load,
.fields = (VMStateField []) {
VMSTATE_UINT64(config, HPETState),
VMSTATE_UINT64(isr, HPETState),
VMSTATE_UINT64(hpet_counter, HPETState),
- VMSTATE_STRUCT_ARRAY(timer, HPETState, HPET_NUM_TIMERS, 0,
- vmstate_hpet_timer, HPETTimer),
+ VMSTATE_UINT8_V(num_timers, HPETState, 2),
+ VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0,
+ vmstate_hpet_timer, HPETTimer),
VMSTATE_END_OF_LIST()
}
};
@@ -212,39 +278,41 @@ static const VMStateDescription vmstate_hpet = {
*/
static void hpet_timer(void *opaque)
{
- HPETTimer *t = (HPETTimer*)opaque;
+ HPETTimer *t = opaque;
uint64_t diff;
uint64_t period = t->period;
- uint64_t cur_tick = hpet_get_ticks();
+ uint64_t cur_tick = hpet_get_ticks(t->state);
if (timer_is_periodic(t) && period != 0) {
if (t->config & HPET_TN_32BIT) {
- while (hpet_time_after(cur_tick, t->cmp))
+ while (hpet_time_after(cur_tick, t->cmp)) {
t->cmp = (uint32_t)(t->cmp + t->period);
- } else
- while (hpet_time_after64(cur_tick, t->cmp))
+ }
+ } else {
+ while (hpet_time_after64(cur_tick, t->cmp)) {
t->cmp += period;
-
+ }
+ }
diff = hpet_calculate_diff(t, cur_tick);
- qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock)
- + (int64_t)ticks_to_ns(diff));
+ qemu_mod_timer(t->qemu_timer,
+ qemu_get_clock(vm_clock) + (int64_t)ticks_to_ns(diff));
} else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) {
if (t->wrap_flag) {
diff = hpet_calculate_diff(t, cur_tick);
- qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock)
- + (int64_t)ticks_to_ns(diff));
+ qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock) +
+ (int64_t)ticks_to_ns(diff));
t->wrap_flag = 0;
}
}
- update_irq(t);
+ update_irq(t, 1);
}
static void hpet_set_timer(HPETTimer *t)
{
uint64_t diff;
uint32_t wrap_diff; /* how many ticks until we wrap? */
- uint64_t cur_tick = hpet_get_ticks();
+ uint64_t cur_tick = hpet_get_ticks(t->state);
/* whenever new timer is being set up, make sure wrap_flag is 0 */
t->wrap_flag = 0;
@@ -260,13 +328,14 @@ static void hpet_set_timer(HPETTimer *t)
t->wrap_flag = 1;
}
}
- qemu_mod_timer(t->qemu_timer, qemu_get_clock(vm_clock)
- + (int64_t)ticks_to_ns(diff));
+ qemu_mod_timer(t->qemu_timer,
+ qemu_get_clock(vm_clock) + (int64_t)ticks_to_ns(diff));
}
static void hpet_del_timer(HPETTimer *t)
{
qemu_del_timer(t->qemu_timer);
+ update_irq(t, 0);
}
#ifdef HPET_DEBUG
@@ -285,7 +354,7 @@ static uint32_t hpet_ram_readw(void *opaque, target_phys_addr_t addr)
static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr)
{
- HPETState *s = (HPETState *)opaque;
+ HPETState *s = opaque;
uint64_t cur_tick, index;
DPRINTF("qemu: Enter hpet_ram_readl at %" PRIx64 "\n", addr);
@@ -293,57 +362,62 @@ static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr)
/*address range of all TN regs*/
if (index >= 0x100 && index <= 0x3ff) {
uint8_t timer_id = (addr - 0x100) / 0x20;
- if (timer_id > HPET_NUM_TIMERS - 1) {
- printf("qemu: timer id out of range\n");
+ HPETTimer *timer = &s->timer[timer_id];
+
+ if (timer_id > s->num_timers) {
+ DPRINTF("qemu: timer id out of range\n");
return 0;
}
- HPETTimer *timer = &s->timer[timer_id];
switch ((addr - 0x100) % 0x20) {
- case HPET_TN_CFG:
- return timer->config;
- case HPET_TN_CFG + 4: // Interrupt capabilities
- return timer->config >> 32;
- case HPET_TN_CMP: // comparator register
- return timer->cmp;
- case HPET_TN_CMP + 4:
- return timer->cmp >> 32;
- case HPET_TN_ROUTE:
- return timer->fsb >> 32;
- default:
- DPRINTF("qemu: invalid hpet_ram_readl\n");
- break;
+ case HPET_TN_CFG:
+ return timer->config;
+ case HPET_TN_CFG + 4: // Interrupt capabilities
+ return timer->config >> 32;
+ case HPET_TN_CMP: // comparator register
+ return timer->cmp;
+ case HPET_TN_CMP + 4:
+ return timer->cmp >> 32;
+ case HPET_TN_ROUTE:
+ return timer->fsb;
+ case HPET_TN_ROUTE + 4:
+ return timer->fsb >> 32;
+ default:
+ DPRINTF("qemu: invalid hpet_ram_readl\n");
+ break;
}
} else {
switch (index) {
- case HPET_ID:
- return s->capability;
- case HPET_PERIOD:
- return s->capability >> 32;
- case HPET_CFG:
- return s->config;
- case HPET_CFG + 4:
- DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl \n");
- return 0;
- case HPET_COUNTER:
- if (hpet_enabled())
- cur_tick = hpet_get_ticks();
- else
- cur_tick = s->hpet_counter;
- DPRINTF("qemu: reading counter = %" PRIx64 "\n", cur_tick);
- return cur_tick;
- case HPET_COUNTER + 4:
- if (hpet_enabled())
- cur_tick = hpet_get_ticks();
- else
- cur_tick = s->hpet_counter;
- DPRINTF("qemu: reading counter + 4 = %" PRIx64 "\n", cur_tick);
- return cur_tick >> 32;
- case HPET_STATUS:
- return s->isr;
- default:
- DPRINTF("qemu: invalid hpet_ram_readl\n");
- break;
+ case HPET_ID:
+ return s->capability;
+ case HPET_PERIOD:
+ return s->capability >> 32;
+ case HPET_CFG:
+ return s->config;
+ case HPET_CFG + 4:
+ DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl \n");
+ return 0;
+ case HPET_COUNTER:
+ if (hpet_enabled(s)) {
+ cur_tick = hpet_get_ticks(s);
+ } else {
+ cur_tick = s->hpet_counter;
+ }
+ DPRINTF("qemu: reading counter = %" PRIx64 "\n", cur_tick);
+ return cur_tick;
+ case HPET_COUNTER + 4:
+ if (hpet_enabled(s)) {
+ cur_tick = hpet_get_ticks(s);
+ } else {
+ cur_tick = s->hpet_counter;
+ }
+ DPRINTF("qemu: reading counter + 4 = %" PRIx64 "\n", cur_tick);
+ return cur_tick >> 32;
+ case HPET_STATUS:
+ return s->isr;
+ default:
+ DPRINTF("qemu: invalid hpet_ram_readl\n");
+ break;
}
}
return 0;
@@ -369,7 +443,7 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
int i;
- HPETState *s = (HPETState *)opaque;
+ HPETState *s = opaque;
uint64_t old_val, new_val, val, index;
DPRINTF("qemu: Enter hpet_ram_writel at %" PRIx64 " = %#x\n", addr, value);
@@ -380,129 +454,151 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
/*address range of all TN regs*/
if (index >= 0x100 && index <= 0x3ff) {
uint8_t timer_id = (addr - 0x100) / 0x20;
- DPRINTF("qemu: hpet_ram_writel timer_id = %#x \n", timer_id);
HPETTimer *timer = &s->timer[timer_id];
+ DPRINTF("qemu: hpet_ram_writel timer_id = %#x \n", timer_id);
+ if (timer_id > s->num_timers) {
+ DPRINTF("qemu: timer id out of range\n");
+ return;
+ }
switch ((addr - 0x100) % 0x20) {
- case HPET_TN_CFG:
- DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n");
- val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
- timer->config = (timer->config & 0xffffffff00000000ULL) | val;
- if (new_val & HPET_TN_32BIT) {
- timer->cmp = (uint32_t)timer->cmp;
- timer->period = (uint32_t)timer->period;
- }
- if (new_val & HPET_TIMER_TYPE_LEVEL) {
- printf("qemu: level-triggered hpet not supported\n");
- exit (-1);
- }
-
- break;
- case HPET_TN_CFG + 4: // Interrupt capabilities
- DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n");
- break;
- case HPET_TN_CMP: // comparator register
- DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP \n");
- if (timer->config & HPET_TN_32BIT)
- new_val = (uint32_t)new_val;
- if (!timer_is_periodic(timer) ||
- (timer->config & HPET_TN_SETVAL))
- timer->cmp = (timer->cmp & 0xffffffff00000000ULL)
- | new_val;
- if (timer_is_periodic(timer)) {
- /*
- * FIXME: Clamp period to reasonable min value?
- * Clamp period to reasonable max value
- */
- new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
- timer->period = (timer->period & 0xffffffff00000000ULL)
- | new_val;
+ case HPET_TN_CFG:
+ DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n");
+ if (activating_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) {
+ update_irq(timer, 0);
+ }
+ val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
+ timer->config = (timer->config & 0xffffffff00000000ULL) | val;
+ if (new_val & HPET_TN_32BIT) {
+ timer->cmp = (uint32_t)timer->cmp;
+ timer->period = (uint32_t)timer->period;
+ }
+ if (activating_bit(old_val, new_val, HPET_TN_ENABLE)) {
+ hpet_set_timer(timer);
+ } else if (deactivating_bit(old_val, new_val, HPET_TN_ENABLE)) {
+ hpet_del_timer(timer);
+ }
+ break;
+ case HPET_TN_CFG + 4: // Interrupt capabilities
+ DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n");
+ break;
+ case HPET_TN_CMP: // comparator register
+ DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP \n");
+ if (timer->config & HPET_TN_32BIT) {
+ new_val = (uint32_t)new_val;
+ }
+ if (!timer_is_periodic(timer)
+ || (timer->config & HPET_TN_SETVAL)) {
+ timer->cmp = (timer->cmp & 0xffffffff00000000ULL) | new_val;
+ }
+ if (timer_is_periodic(timer)) {
+ /*
+ * FIXME: Clamp period to reasonable min value?
+ * Clamp period to reasonable max value
+ */
+ new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
+ timer->period =
+ (timer->period & 0xffffffff00000000ULL) | new_val;
+ }
+ timer->config &= ~HPET_TN_SETVAL;
+ if (hpet_enabled(s)) {
+ hpet_set_timer(timer);
+ }
+ break;
+ case HPET_TN_CMP + 4: // comparator register high order
+ DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP + 4\n");
+ if (!timer_is_periodic(timer)
+ || (timer->config & HPET_TN_SETVAL)) {
+ timer->cmp = (timer->cmp & 0xffffffffULL) | new_val << 32;
+ } else {
+ /*
+ * FIXME: Clamp period to reasonable min value?
+ * Clamp period to reasonable max value
+ */
+ new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
+ timer->period =
+ (timer->period & 0xffffffffULL) | new_val << 32;
}
timer->config &= ~HPET_TN_SETVAL;
- if (hpet_enabled())
+ if (hpet_enabled(s)) {
hpet_set_timer(timer);
- break;
- case HPET_TN_CMP + 4: // comparator register high order
- DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP + 4\n");
- if (!timer_is_periodic(timer) ||
- (timer->config & HPET_TN_SETVAL))
- timer->cmp = (timer->cmp & 0xffffffffULL)
- | new_val << 32;
- else {
- /*
- * FIXME: Clamp period to reasonable min value?
- * Clamp period to reasonable max value
- */
- new_val &= (timer->config
- & HPET_TN_32BIT ? ~0u : ~0ull) >> 1;
- timer->period = (timer->period & 0xffffffffULL)
- | new_val << 32;
}
- timer->config &= ~HPET_TN_SETVAL;
- if (hpet_enabled())
- hpet_set_timer(timer);
- break;
- case HPET_TN_ROUTE + 4:
- DPRINTF("qemu: hpet_ram_writel HPET_TN_ROUTE + 4\n");
- break;
- default:
- DPRINTF("qemu: invalid hpet_ram_writel\n");
break;
+ case HPET_TN_ROUTE:
+ timer->fsb = (timer->fsb & 0xffffffff00000000ULL) | new_val;
+ break;
+ case HPET_TN_ROUTE + 4:
+ timer->fsb = (new_val << 32) | (timer->fsb & 0xffffffff);
+ break;
+ default:
+ DPRINTF("qemu: invalid hpet_ram_writel\n");
+ break;
}
return;
} else {
switch (index) {
- case HPET_ID:
- return;
- case HPET_CFG:
- val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
- s->config = (s->config & 0xffffffff00000000ULL) | val;
- if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
- /* Enable main counter and interrupt generation. */
- s->hpet_offset = ticks_to_ns(s->hpet_counter)
- - qemu_get_clock(vm_clock);
- for (i = 0; i < HPET_NUM_TIMERS; i++)
- if ((&s->timer[i])->cmp != ~0ULL)
- hpet_set_timer(&s->timer[i]);
+ case HPET_ID:
+ return;
+ case HPET_CFG:
+ val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK);
+ s->config = (s->config & 0xffffffff00000000ULL) | val;
+ if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
+ /* Enable main counter and interrupt generation. */
+ s->hpet_offset =
+ ticks_to_ns(s->hpet_counter) - qemu_get_clock(vm_clock);
+ for (i = 0; i < s->num_timers; i++) {
+ if ((&s->timer[i])->cmp != ~0ULL) {
+ hpet_set_timer(&s->timer[i]);
+ }
}
- else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
- /* Halt main counter and disable interrupt generation. */
- s->hpet_counter = hpet_get_ticks();
- for (i = 0; i < HPET_NUM_TIMERS; i++)
- hpet_del_timer(&s->timer[i]);
+ } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
+ /* Halt main counter and disable interrupt generation. */
+ s->hpet_counter = hpet_get_ticks(s);
+ for (i = 0; i < s->num_timers; i++) {
+ hpet_del_timer(&s->timer[i]);
}
- /* i8254 and RTC are disabled when HPET is in legacy mode */
- if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
- hpet_pit_disable();
- } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
- hpet_pit_enable();
+ }
+ /* i8254 and RTC are disabled when HPET is in legacy mode */
+ if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
+ hpet_pit_disable();
+ qemu_irq_lower(s->irqs[RTC_ISA_IRQ]);
+ } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
+ hpet_pit_enable();
+ qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level);
+ }
+ break;
+ case HPET_CFG + 4:
+ DPRINTF("qemu: invalid HPET_CFG+4 write \n");
+ break;
+ case HPET_STATUS:
+ val = new_val & s->isr;
+ for (i = 0; i < s->num_timers; i++) {
+ if (val & (1 << i)) {
+ update_irq(&s->timer[i], 0);
}
- break;
- case HPET_CFG + 4:
- DPRINTF("qemu: invalid HPET_CFG+4 write \n");
- break;
- case HPET_STATUS:
- /* FIXME: need to handle level-triggered interrupts */
- break;
- case HPET_COUNTER:
- if (hpet_enabled())
- printf("qemu: Writing counter while HPET enabled!\n");
- s->hpet_counter = (s->hpet_counter & 0xffffffff00000000ULL)
- | value;
- DPRINTF("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n",
- value, s->hpet_counter);
- break;
- case HPET_COUNTER + 4:
- if (hpet_enabled())
- printf("qemu: Writing counter while HPET enabled!\n");
- s->hpet_counter = (s->hpet_counter & 0xffffffffULL)
- | (((uint64_t)value) << 32);
- DPRINTF("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n",
- value, s->hpet_counter);
- break;
- default:
- DPRINTF("qemu: invalid hpet_ram_writel\n");
- break;
+ }
+ break;
+ case HPET_COUNTER:
+ if (hpet_enabled(s)) {
+ DPRINTF("qemu: Writing counter while HPET enabled!\n");
+ }
+ s->hpet_counter =
+ (s->hpet_counter & 0xffffffff00000000ULL) | value;
+ DPRINTF("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n",
+ value, s->hpet_counter);
+ break;
+ case HPET_COUNTER + 4:
+ if (hpet_enabled(s)) {
+ DPRINTF("qemu: Writing counter while HPET enabled!\n");
+ }
+ s->hpet_counter =
+ (s->hpet_counter & 0xffffffffULL) | (((uint64_t)value) << 32);
+ DPRINTF("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n",
+ value, s->hpet_counter);
+ break;
+ default:
+ DPRINTF("qemu: invalid hpet_ram_writel\n");
+ break;
}
}
}
@@ -529,58 +625,104 @@ static CPUWriteMemoryFunc * const hpet_ram_write[] = {
hpet_ram_writel,
};
-static void hpet_reset(void *opaque) {
- HPETState *s = opaque;
+static void hpet_reset(DeviceState *d)
+{
+ HPETState *s = FROM_SYSBUS(HPETState, sysbus_from_qdev(d));
int i;
static int count = 0;
- for (i=0; i<HPET_NUM_TIMERS; i++) {
+ for (i = 0; i < s->num_timers; i++) {
HPETTimer *timer = &s->timer[i];
+
hpet_del_timer(timer);
- timer->tn = i;
timer->cmp = ~0ULL;
- timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
+ timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
+ if (s->flags & (1 << HPET_MSI_SUPPORT)) {
+ timer->config |= HPET_TN_FSB_CAP;
+ }
/* advertise availability of ioapic inti2 */
timer->config |= 0x00000004ULL << 32;
- timer->state = s;
timer->period = 0ULL;
timer->wrap_flag = 0;
}
s->hpet_counter = 0ULL;
s->hpet_offset = 0ULL;
- /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
- s->capability = 0x8086a201ULL;
+ /* 64-bit main counter; LegacyReplacementRoute. */
+ s->capability = 0x8086a001ULL;
+ s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT;
s->capability |= ((HPET_CLK_PERIOD) << 32);
s->config = 0ULL;
- if (count > 0)
+ if (count > 0) {
/* we don't enable pit when hpet_reset is first called (by hpet_init)
* because hpet is taking over for pit here. On subsequent invocations,
* hpet_reset is called due to system reset. At this point control must
* be returned to pit until SW reenables hpet.
*/
hpet_pit_enable();
+ }
count = 1;
}
+static void hpet_handle_rtc_irq(void *opaque, int n, int level)
+{
+ HPETState *s = FROM_SYSBUS(HPETState, opaque);
+
+ s->rtc_irq_level = level;
+ if (!hpet_in_legacy_mode(s)) {
+ qemu_set_irq(s->irqs[RTC_ISA_IRQ], level);
+ }
+}
-void hpet_init(qemu_irq *irq) {
+static int hpet_init(SysBusDevice *dev)
+{
+ HPETState *s = FROM_SYSBUS(HPETState, dev);
int i, iomemtype;
- HPETState *s;
+ HPETTimer *timer;
- DPRINTF ("hpet_init\n");
+ for (i = 0; i < HPET_NUM_IRQ_ROUTES; i++) {
+ sysbus_init_irq(dev, &s->irqs[i]);
+ }
- s = qemu_mallocz(sizeof(HPETState));
- hpet_statep = s;
- s->irqs = irq;
- for (i=0; i<HPET_NUM_TIMERS; i++) {
- HPETTimer *timer = &s->timer[i];
+ if (s->num_timers < HPET_MIN_TIMERS) {
+ s->num_timers = HPET_MIN_TIMERS;
+ } else if (s->num_timers > HPET_MAX_TIMERS) {
+ s->num_timers = HPET_MAX_TIMERS;
+ }
+ for (i = 0; i < HPET_MAX_TIMERS; i++) {
+ timer = &s->timer[i];
timer->qemu_timer = qemu_new_timer(vm_clock, hpet_timer, timer);
+ timer->tn = i;
+ timer->state = s;
}
- vmstate_register(-1, &vmstate_hpet, s);
- qemu_register_reset(hpet_reset, s);
+
+ isa_reserve_irq(RTC_ISA_IRQ);
+ qdev_init_gpio_in(&dev->qdev, hpet_handle_rtc_irq, 1);
+
/* HPET Area */
iomemtype = cpu_register_io_memory(hpet_ram_read,
hpet_ram_write, s);
- cpu_register_physical_memory(HPET_BASE, 0x400, iomemtype);
+ sysbus_init_mmio(dev, 0x400, iomemtype);
+ return 0;
}
+
+static SysBusDeviceInfo hpet_device_info = {
+ .qdev.name = "hpet",
+ .qdev.size = sizeof(HPETState),
+ .qdev.no_user = 1,
+ .qdev.vmsd = &vmstate_hpet,
+ .qdev.reset = hpet_reset,
+ .init = hpet_init,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
+ DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
+
+static void hpet_register_device(void)
+{
+ sysbus_register_withprop(&hpet_device_info);
+}
+
+device_init(hpet_register_device)
diff --git a/hw/hpet_emul.h b/hw/hpet_emul.h
index cfd95b4..d7bc102 100644
--- a/hw/hpet_emul.h
+++ b/hw/hpet_emul.h
@@ -17,8 +17,10 @@
#define HPET_CLK_PERIOD 10000000ULL /* 10000000 femtoseconds == 10ns*/
#define FS_PER_NS 1000000
-#define HPET_NUM_TIMERS 3
-#define HPET_TIMER_TYPE_LEVEL 0x002
+#define HPET_MIN_TIMERS 3
+#define HPET_MAX_TIMERS 32
+
+#define HPET_NUM_IRQ_ROUTES 32
#define HPET_CFG_ENABLE 0x001
#define HPET_CFG_LEGACY 0x002
@@ -33,7 +35,10 @@
#define HPET_TN_ROUTE 0x010
#define HPET_CFG_WRITE_MASK 0x3
+#define HPET_ID_NUM_TIM_SHIFT 8
+#define HPET_ID_NUM_TIM_MASK 0x1f00
+#define HPET_TN_TYPE_LEVEL 0x002
#define HPET_TN_ENABLE 0x004
#define HPET_TN_PERIODIC 0x008
#define HPET_TN_PERIODIC_CAP 0x010
@@ -41,42 +46,11 @@
#define HPET_TN_SETVAL 0x040
#define HPET_TN_32BIT 0x100
#define HPET_TN_INT_ROUTE_MASK 0x3e00
-#define HPET_TN_CFG_WRITE_MASK 0x3f4e
+#define HPET_TN_FSB_ENABLE 0x4000
+#define HPET_TN_FSB_CAP 0x8000
+#define HPET_TN_CFG_WRITE_MASK 0x7f4e
#define HPET_TN_INT_ROUTE_SHIFT 9
#define HPET_TN_INT_ROUTE_CAP_SHIFT 32
#define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U
-struct HPETState;
-typedef struct HPETTimer { /* timers */
- uint8_t tn; /*timer number*/
- QEMUTimer *qemu_timer;
- struct HPETState *state;
- /* Memory-mapped, software visible timer registers */
- uint64_t config; /* configuration/cap */
- uint64_t cmp; /* comparator */
- uint64_t fsb; /* FSB route, not supported now */
- /* Hidden register state */
- uint64_t period; /* Last value written to comparator */
- uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit
- * mode. Next pop will be actual timer expiration.
- */
-} HPETTimer;
-
-typedef struct HPETState {
- uint64_t hpet_offset;
- qemu_irq *irqs;
- HPETTimer timer[HPET_NUM_TIMERS];
-
- /* Memory-mapped, software visible registers */
- uint64_t capability; /* capabilities */
- uint64_t config; /* configuration */
- uint64_t isr; /* interrupt status reg */
- uint64_t hpet_counter; /* main counter */
-} HPETState;
-
-#if defined TARGET_I386
-extern uint32_t hpet_in_legacy_mode(void);
-extern void hpet_init(qemu_irq *irq);
-#endif
-
#endif
diff --git a/hw/hw.h b/hw/hw.h
index fc2d184..a49d866 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -8,7 +8,6 @@
#include "cpu-common.h"
#endif
-#include <stdbool.h>
#include "ioport.h"
#include "irq.h"
@@ -474,6 +473,16 @@ extern const VMStateInfo vmstate_info_unused_buffer;
.offset = vmstate_offset_array(_state, _field, _type, _num), \
}
+#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \
+ .version_id = (_version), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT|VMS_VARRAY_INT32, \
+ .offset = offsetof(_state, _field), \
+}
+
#define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) { \
.name = (stringify(_field)), \
.version_id = (_version), \
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index c3e6a70..c3459bf 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -27,7 +27,6 @@
#include "pc.h"
#include "apic.h"
#include "isa.h"
-#include "hpet_emul.h"
#include "mc146818rtc.h"
//#define DEBUG_CMOS
@@ -101,19 +100,6 @@ typedef struct RTCState {
QEMUTimer *second_timer2;
} RTCState;
-static void rtc_irq_raise(qemu_irq irq)
-{
- /* When HPET is operating in legacy mode, RTC interrupts are disabled
- * We block qemu_irq_raise, but not qemu_irq_lower, in case legacy
- * mode is established while interrupt is raised. We want it to
- * be lowered in any case
- */
-#if defined TARGET_I386
- if (!hpet_in_legacy_mode())
-#endif
- qemu_irq_raise(irq);
-}
-
static void rtc_set_time(RTCState *s);
static void rtc_copy_date(RTCState *s);
@@ -139,7 +125,7 @@ static void rtc_coalesced_timer(void *opaque)
apic_reset_irq_delivered();
s->cmos_data[RTC_REG_C] |= 0xc0;
DPRINTF_C("cmos: injecting from timer\n");
- rtc_irq_raise(s->irq);
+ qemu_irq_raise(s->irq);
if (apic_get_irq_delivered()) {
s->irq_coalesced--;
DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
@@ -155,19 +141,10 @@ static void rtc_timer_update(RTCState *s, int64_t current_time)
{
int period_code, period;
int64_t cur_clock, next_irq_clock;
- int enable_pie;
period_code = s->cmos_data[RTC_REG_A] & 0x0f;
-#if defined TARGET_I386
- /* disable periodic timer if hpet is in legacy mode, since interrupts are
- * disabled anyway.
- */
- enable_pie = !hpet_in_legacy_mode();
-#else
- enable_pie = 1;
-#endif
if (period_code != 0
- && (((s->cmos_data[RTC_REG_B] & REG_B_PIE) && enable_pie)
+ && ((s->cmos_data[RTC_REG_B] & REG_B_PIE)
|| ((s->cmos_data[RTC_REG_B] & REG_B_SQWE) && s->sqw_irq))) {
if (period_code <= 2)
period_code += 7;
@@ -206,7 +183,7 @@ static void rtc_periodic_timer(void *opaque)
if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT)
s->irq_reinject_on_ack_count = 0;
apic_reset_irq_delivered();
- rtc_irq_raise(s->irq);
+ qemu_irq_raise(s->irq);
if (!apic_get_irq_delivered()) {
s->irq_coalesced++;
rtc_coalesced_timer_update(s);
@@ -215,7 +192,7 @@ static void rtc_periodic_timer(void *opaque)
}
} else
#endif
- rtc_irq_raise(s->irq);
+ qemu_irq_raise(s->irq);
}
if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) {
/* Not square wave at all but we don't want 2048Hz interrupts!
@@ -444,15 +421,15 @@ static void rtc_update_second2(void *opaque)
s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
s->cmos_data[RTC_REG_C] |= 0xa0;
- rtc_irq_raise(s->irq);
+ qemu_irq_raise(s->irq);
}
}
/* update ended interrupt */
s->cmos_data[RTC_REG_C] |= REG_C_UF;
if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
- s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
- rtc_irq_raise(s->irq);
+ s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
+ qemu_irq_raise(s->irq);
}
/* clear update in progress bit */
@@ -606,9 +583,6 @@ static int rtc_initfn(ISADevice *dev)
{
RTCState *s = DO_UPCAST(RTCState, dev, dev);
int base = 0x70;
- int isairq = 8;
-
- isa_init_irq(dev, &s->irq, isairq);
s->cmos_data[RTC_REG_A] = 0x26;
s->cmos_data[RTC_REG_B] = 0x02;
@@ -638,13 +612,20 @@ static int rtc_initfn(ISADevice *dev)
return 0;
}
-ISADevice *rtc_init(int base_year)
+ISADevice *rtc_init(int base_year, qemu_irq intercept_irq)
{
ISADevice *dev;
+ RTCState *s;
dev = isa_create("mc146818rtc");
+ s = DO_UPCAST(RTCState, dev, dev);
qdev_prop_set_int32(&dev->qdev, "base_year", base_year);
qdev_init_nofail(&dev->qdev);
+ if (intercept_irq) {
+ s->irq = intercept_irq;
+ } else {
+ isa_init_irq(dev, &s->irq, RTC_ISA_IRQ);
+ }
return dev;
}
diff --git a/hw/mc146818rtc.h b/hw/mc146818rtc.h
index 6f46a68..575968c 100644
--- a/hw/mc146818rtc.h
+++ b/hw/mc146818rtc.h
@@ -3,7 +3,9 @@
#include "isa.h"
-ISADevice *rtc_init(int base_year);
+#define RTC_ISA_IRQ 8
+
+ISADevice *rtc_init(int base_year, qemu_irq intercept_irq);
void rtc_set_memory(ISADevice *dev, int addr, int val);
void rtc_set_date(ISADevice *dev, const struct tm *tm);
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index ead3a00..22db7a2 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -259,7 +259,7 @@ void mips_jazz_init (ram_addr_t ram_size,
fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds);
/* Real time clock */
- rtc_init(1980);
+ rtc_init(1980, NULL);
s_rtc = cpu_register_io_memory(rtc_read, rtc_write, NULL);
cpu_register_physical_memory(0x80004000, 0x00001000, s_rtc);
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index a8f9d15..23de7f0 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -959,7 +959,7 @@ void mips_malta_init (ram_addr_t ram_size,
/* Super I/O */
isa_dev = isa_create_simple("i8042");
- rtc_state = rtc_init(2000);
+ rtc_state = rtc_init(2000, NULL);
serial_isa_init(0, serial_hds[0]);
serial_isa_init(1, serial_hds[1]);
if (parallel_hds[0])
diff --git a/hw/mips_mipssim.c b/hw/mips_mipssim.c
index a747de5..293d99e 100644
--- a/hw/mips_mipssim.c
+++ b/hw/mips_mipssim.c
@@ -106,7 +106,10 @@ static void main_cpu_reset(void *opaque)
CPUState *env = s->env;
cpu_reset(env);
- env->active_tc.PC = s->vector;
+ env->active_tc.PC = s->vector & ~(target_ulong)1;
+ if (s->vector & 1) {
+ env->hflags |= MIPS_HFLAG_M16;
+ }
}
static void
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index f1fcfcd..5a96dea 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -267,7 +267,7 @@ void mips_r4k_init (ram_addr_t ram_size,
isa_bus_new(NULL);
isa_bus_irqs(i8259);
- rtc_state = rtc_init(2000);
+ rtc_state = rtc_init(2000, NULL);
/* Register 64 KB of ISA IO space at 0x14000000 */
#ifdef TARGET_WORDS_BIGENDIAN
diff --git a/hw/multiboot.c b/hw/multiboot.c
index a1b665c..dc980e6 100644
--- a/hw/multiboot.c
+++ b/hw/multiboot.c
@@ -118,7 +118,8 @@ static void mb_add_mod(MultibootState *s,
stl_p(p + MB_MOD_END, end);
stl_p(p + MB_MOD_CMDLINE, cmdline_phys);
- mb_debug("mod%02d: %08x - %08x\n", s->mb_mods_count, start, end);
+ mb_debug("mod%02d: "TARGET_FMT_plx" - "TARGET_FMT_plx"\n",
+ s->mb_mods_count, start, end);
s->mb_mods_count++;
}
@@ -276,7 +277,7 @@ int load_multiboot(void *fw_cfg,
mb_add_mod(&mbs, mbs.mb_buf_phys + offs,
mbs.mb_buf_phys + offs + mb_mod_length, c);
- mb_debug("mod_start: %p\nmod_end: %p\n cmdline: %#x\n",
+ mb_debug("mod_start: %p\nmod_end: %p\n cmdline: "TARGET_FMT_plx"\n",
(char *)mbs.mb_buf + offs,
(char *)mbs.mb_buf + offs + mb_mod_length, c);
initrd_filename = next_initrd+1;
@@ -304,8 +305,8 @@ int load_multiboot(void *fw_cfg,
stl_p(bootinfo + MBI_MMAP_ADDR, ADDR_E820_MAP);
mb_debug("multiboot: mh_entry_addr = %#x\n", mh_entry_addr);
- mb_debug(" mb_buf_phys = %x\n", mbs.mb_buf_phys);
- mb_debug(" mod_start = %x\n", mbs.mb_buf_phys + mbs.offset_mods);
+ mb_debug(" mb_buf_phys = "TARGET_FMT_plx"\n", mbs.mb_buf_phys);
+ mb_debug(" mod_start = "TARGET_FMT_plx"\n", mbs.mb_buf_phys + mbs.offset_mods);
mb_debug(" mb_mods_count = %d\n", mbs.mb_mods_count);
/* save bootinfo off the stack */
diff --git a/hw/pc.c b/hw/pc.c
index 6e7c468..0f7d330 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -35,6 +35,7 @@
#include "elf.h"
#include "multiboot.h"
#include "mc146818rtc.h"
+#include "sysbus.h"
#include "sysemu.h"
/* output Bochs bios info messages */
@@ -943,6 +944,7 @@ void pc_basic_device_init(qemu_irq *isa_irq,
int i;
DriveInfo *fd[MAX_FD];
PITState *pit;
+ qemu_irq rtc_irq = NULL;
qemu_irq *a20_line;
ISADevice *i8042;
qemu_irq *cpu_exit_irq;
@@ -951,15 +953,20 @@ void pc_basic_device_init(qemu_irq *isa_irq,
register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
- *rtc_state = rtc_init(2000);
+ if (!no_hpet) {
+ DeviceState *hpet = sysbus_create_simple("hpet", HPET_BASE, NULL);
+
+ for (i = 0; i < 24; i++) {
+ sysbus_connect_irq(sysbus_from_qdev(hpet), i, isa_irq[i]);
+ }
+ rtc_irq = qdev_get_gpio_in(hpet, 0);
+ }
+ *rtc_state = rtc_init(2000, rtc_irq);
qemu_register_boot_set(pc_boot_set, *rtc_state);
pit = pit_init(0x40, isa_reserve_irq(0));
pcspk_init(pit);
- if (!no_hpet) {
- hpet_init(isa_irq);
- }
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c
index 93344b1..cdde991 100644
--- a/hw/petalogix_s3adsp1800_mmu.c
+++ b/hw/petalogix_s3adsp1800_mmu.c
@@ -185,12 +185,12 @@ petalogix_s3adsp1800_init(ram_addr_t ram_size,
boot_info.bootstrap_pc = ddr_base;
}
- boot_info.cmdline = ddr_base + kernel_size + 8192;
+ boot_info.cmdline = high + 4096;
if (kernel_cmdline && strlen(kernel_cmdline)) {
pstrcpy_targphys("cmdline", boot_info.cmdline, 256, kernel_cmdline);
}
/* Provide a device-tree. */
- boot_info.fdt = boot_info.cmdline + 256;
+ boot_info.fdt = boot_info.cmdline + 4096;
petalogix_load_device_tree(boot_info.fdt, ram_size,
0, 0,
kernel_cmdline);
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 16c9950..bb9e15f 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -696,7 +696,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
pci_vga_init(pci_bus, 0, 0);
// openpic = openpic_init(0x00000000, 0xF0000000, 1);
// pit = pit_init(0x40, i8259[0]);
- rtc_init(2000);
+ rtc_init(2000, NULL);
if (serial_hds[0])
serial_isa_init(0, serial_hds[0]);
diff --git a/hw/qdev.c b/hw/qdev.c
index 29f6e9f..61f999c 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -706,6 +706,7 @@ void qbus_free(BusState *bus)
QLIST_REMOVE(bus, sibling);
bus->parent->num_child_bus--;
}
+ qemu_free((void*)bus->name);
if (bus->qdev_allocated) {
qemu_free(bus);
}
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 9f80e15..c60fd8d 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1415,6 +1415,8 @@ static uint32_t ohci_mem_read(void *ptr, target_phys_addr_t addr)
OHCIState *ohci = ptr;
uint32_t retval;
+ addr &= 0xff;
+
/* Only aligned reads are allowed on OHCI */
if (addr & 3) {
fprintf(stderr, "usb-ohci: Mis-aligned read\n");
@@ -1538,6 +1540,8 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
{
OHCIState *ohci = ptr;
+ addr &= 0xff;
+
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val);
#endif
diff --git a/hw/vga-isa-mm.c b/hw/vga-isa-mm.c
index 2faefa5..8e31e36 100644
--- a/hw/vga-isa-mm.c
+++ b/hw/vga-isa-mm.c
@@ -121,10 +121,6 @@ int isa_vga_mm_init(target_phys_addr_t vram_base,
s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate,
s->vga.screen_dump, s->vga.text_update, s);
-#ifdef CONFIG_BOCHS_VBE
- /* XXX: use optimized standard vga accesses */
- cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
- VGA_RAM_SIZE, s->vga.vram_offset);
-#endif
+ vga_init_vbe(&s->vga);
return 0;
}
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index cb664e6..06ba481 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -532,16 +532,17 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
if (!virtio_net_can_receive(&n->nic->nc))
return -1;
- if (!virtio_net_has_buffers(n, size))
+ /* hdr_len refers to the header we supply to the guest */
+ hdr_len = n->mergeable_rx_bufs ?
+ sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);
+
+
+ if (!virtio_net_has_buffers(n, size + hdr_len))
return 0;
if (!receive_filter(n, buf, size))
return size;
- /* hdr_len refers to the header we supply to the guest */
- hdr_len = n->mergeable_rx_bufs ?
- sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);
-
offset = i = 0;
while (offset < size) {
@@ -555,7 +556,9 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
virtqueue_pop(n->rx_vq, &elem) == 0) {
if (i == 0)
return -1;
- fprintf(stderr, "virtio-net truncating packet\n");
+ fprintf(stderr, "virtio-net truncating packet: "
+ "offset %zd, size %zd, hdr_len %zd\n",
+ offset, size, hdr_len);
exit(1);
}
@@ -877,12 +880,11 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
static void virtio_net_vmstate_change(void *opaque, int running, int reason)
{
VirtIONet *n = opaque;
- if (!running) {
- return;
- }
- /* This is called when vm is started, it will start vhost backend if
- * appropriate e.g. after migration. */
- virtio_net_set_status(&n->vdev, n->vdev.status);
+ uint8_t status = running ? VIRTIO_CONFIG_S_DRIVER_OK : 0;
+ /* This is called when vm is started/stopped,
+ * it will start/stop vhost backend if * appropriate
+ * e.g. after migration. */
+ virtio_net_set_status(&n->vdev, n->vdev.status & status);
}
VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf)
diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
index a93b545..ff08c40 100644
--- a/hw/virtio-serial.h
+++ b/hw/virtio-serial.h
@@ -15,7 +15,6 @@
#ifndef _QEMU_VIRTIO_SERIAL_H
#define _QEMU_VIRTIO_SERIAL_H
-#include <stdbool.h>
#include "qdev.h"
#include "virtio.h"
diff --git a/hw/xenfb.c b/hw/xenfb.c
index 422cd53..da5297b 100644
--- a/hw/xenfb.c
+++ b/hw/xenfb.c
@@ -29,7 +29,6 @@
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
-#include <stdbool.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdio.h>
diff --git a/hxtool b/hxtool
index d499dc0..7ca83ed 100644
--- a/hxtool
+++ b/hxtool
@@ -59,6 +59,7 @@ hxtoqmp()
{
IFS=
flag=0
+ line=1
while read -r str; do
case "$str" in
HXCOMM*)
@@ -87,6 +88,7 @@ hxtoqmp()
test $flag -eq 1 && echo "$str"
;;
esac
+ line=$((line+1))
done
}
diff --git a/json-lexer.c b/json-lexer.c
index 9d64920..c736f42 100644
--- a/json-lexer.c
+++ b/json-lexer.c
@@ -29,7 +29,6 @@
enum json_lexer_state {
ERROR = 0,
- IN_DONE_STRING,
IN_DQ_UCODE3,
IN_DQ_UCODE2,
IN_DQ_UCODE1,
@@ -57,19 +56,19 @@ enum json_lexer_state {
IN_ESCAPE_I,
IN_ESCAPE_I6,
IN_ESCAPE_I64,
- IN_ESCAPE_DONE,
IN_WHITESPACE,
- IN_OPERATOR_DONE,
IN_START,
};
#define TERMINAL(state) [0 ... 0x7F] = (state)
-static const uint8_t json_lexer[][256] = {
- [IN_DONE_STRING] = {
- TERMINAL(JSON_STRING),
- },
+/* Return whether TERMINAL is a terminal state and the transition to it
+ from OLD_STATE required lookahead. This happens whenever the table
+ below uses the TERMINAL macro. */
+#define TERMINAL_NEEDED_LOOKAHEAD(old_state, terminal) \
+ (json_lexer[(old_state)][0] == (terminal))
+static const uint8_t json_lexer[][256] = {
/* double quote string */
[IN_DQ_UCODE3] = {
['0' ... '9'] = IN_DQ_STRING,
@@ -97,6 +96,8 @@ static const uint8_t json_lexer[][256] = {
['n'] = IN_DQ_STRING,
['r'] = IN_DQ_STRING,
['t'] = IN_DQ_STRING,
+ ['/'] = IN_DQ_STRING,
+ ['\\'] = IN_DQ_STRING,
['\''] = IN_DQ_STRING,
['\"'] = IN_DQ_STRING,
['u'] = IN_DQ_UCODE0,
@@ -104,7 +105,7 @@ static const uint8_t json_lexer[][256] = {
[IN_DQ_STRING] = {
[1 ... 0xFF] = IN_DQ_STRING,
['\\'] = IN_DQ_STRING_ESCAPE,
- ['"'] = IN_DONE_STRING,
+ ['"'] = JSON_STRING,
},
/* single quote string */
@@ -134,6 +135,8 @@ static const uint8_t json_lexer[][256] = {
['n'] = IN_SQ_STRING,
['r'] = IN_SQ_STRING,
['t'] = IN_SQ_STRING,
+ ['/'] = IN_DQ_STRING,
+ ['\\'] = IN_DQ_STRING,
['\''] = IN_SQ_STRING,
['\"'] = IN_SQ_STRING,
['u'] = IN_SQ_UCODE0,
@@ -141,7 +144,7 @@ static const uint8_t json_lexer[][256] = {
[IN_SQ_STRING] = {
[1 ... 0xFF] = IN_SQ_STRING,
['\\'] = IN_SQ_STRING_ESCAPE,
- ['\''] = IN_DONE_STRING,
+ ['\''] = JSON_STRING,
},
/* Zero */
@@ -207,27 +210,18 @@ static const uint8_t json_lexer[][256] = {
['\n'] = IN_WHITESPACE,
},
- /* operator */
- [IN_OPERATOR_DONE] = {
- TERMINAL(JSON_OPERATOR),
- },
-
/* escape */
- [IN_ESCAPE_DONE] = {
- TERMINAL(JSON_ESCAPE),
- },
-
[IN_ESCAPE_LL] = {
- ['d'] = IN_ESCAPE_DONE,
+ ['d'] = JSON_ESCAPE,
},
[IN_ESCAPE_L] = {
- ['d'] = IN_ESCAPE_DONE,
+ ['d'] = JSON_ESCAPE,
['l'] = IN_ESCAPE_LL,
},
[IN_ESCAPE_I64] = {
- ['d'] = IN_ESCAPE_DONE,
+ ['d'] = JSON_ESCAPE,
},
[IN_ESCAPE_I6] = {
@@ -239,11 +233,11 @@ static const uint8_t json_lexer[][256] = {
},
[IN_ESCAPE] = {
- ['d'] = IN_ESCAPE_DONE,
- ['i'] = IN_ESCAPE_DONE,
- ['p'] = IN_ESCAPE_DONE,
- ['s'] = IN_ESCAPE_DONE,
- ['f'] = IN_ESCAPE_DONE,
+ ['d'] = JSON_ESCAPE,
+ ['i'] = JSON_ESCAPE,
+ ['p'] = JSON_ESCAPE,
+ ['s'] = JSON_ESCAPE,
+ ['f'] = JSON_ESCAPE,
['l'] = IN_ESCAPE_L,
['I'] = IN_ESCAPE_I,
},
@@ -255,12 +249,12 @@ static const uint8_t json_lexer[][256] = {
['0'] = IN_ZERO,
['1' ... '9'] = IN_NONZERO_NUMBER,
['-'] = IN_NEG_NONZERO_NUMBER,
- ['{'] = IN_OPERATOR_DONE,
- ['}'] = IN_OPERATOR_DONE,
- ['['] = IN_OPERATOR_DONE,
- [']'] = IN_OPERATOR_DONE,
- [','] = IN_OPERATOR_DONE,
- [':'] = IN_OPERATOR_DONE,
+ ['{'] = JSON_OPERATOR,
+ ['}'] = JSON_OPERATOR,
+ ['['] = JSON_OPERATOR,
+ [']'] = JSON_OPERATOR,
+ [','] = JSON_OPERATOR,
+ [':'] = JSON_OPERATOR,
['a' ... 'z'] = IN_KEYWORD,
['%'] = IN_ESCAPE,
[' '] = IN_WHITESPACE,
@@ -275,11 +269,12 @@ void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func)
lexer->emit = func;
lexer->state = IN_START;
lexer->token = qstring_new();
+ lexer->x = lexer->y = 0;
}
static int json_lexer_feed_char(JSONLexer *lexer, char ch)
{
- char buf[2];
+ int char_consumed, new_state;
lexer->x++;
if (ch == '\n') {
@@ -287,32 +282,33 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch)
lexer->y++;
}
- lexer->state = json_lexer[lexer->state][(uint8_t)ch];
-
- switch (lexer->state) {
- case JSON_OPERATOR:
- case JSON_ESCAPE:
- case JSON_INTEGER:
- case JSON_FLOAT:
- case JSON_KEYWORD:
- case JSON_STRING:
- lexer->emit(lexer, lexer->token, lexer->state, lexer->x, lexer->y);
- case JSON_SKIP:
- lexer->state = json_lexer[IN_START][(uint8_t)ch];
- QDECREF(lexer->token);
- lexer->token = qstring_new();
- break;
- case ERROR:
- return -EINVAL;
- default:
- break;
- }
-
- buf[0] = ch;
- buf[1] = 0;
-
- qstring_append(lexer->token, buf);
+ do {
+ new_state = json_lexer[lexer->state][(uint8_t)ch];
+ char_consumed = !TERMINAL_NEEDED_LOOKAHEAD(lexer->state, new_state);
+ if (char_consumed) {
+ qstring_append_chr(lexer->token, ch);
+ }
+ switch (new_state) {
+ case JSON_OPERATOR:
+ case JSON_ESCAPE:
+ case JSON_INTEGER:
+ case JSON_FLOAT:
+ case JSON_KEYWORD:
+ case JSON_STRING:
+ lexer->emit(lexer, lexer->token, new_state, lexer->x, lexer->y);
+ case JSON_SKIP:
+ QDECREF(lexer->token);
+ lexer->token = qstring_new();
+ new_state = IN_START;
+ break;
+ case ERROR:
+ return -EINVAL;
+ default:
+ break;
+ }
+ lexer->state = new_state;
+ } while (!char_consumed);
return 0;
}
@@ -334,7 +330,7 @@ int json_lexer_feed(JSONLexer *lexer, const char *buffer, size_t size)
int json_lexer_flush(JSONLexer *lexer)
{
- return json_lexer_feed_char(lexer, 0);
+ return lexer->state == IN_START ? 0 : json_lexer_feed_char(lexer, 0);
}
void json_lexer_destroy(JSONLexer *lexer)
diff --git a/json-parser.c b/json-parser.c
index b55d763..70b9b6f 100644
--- a/json-parser.c
+++ b/json-parser.c
@@ -11,7 +11,6 @@
*
*/
-#include <stdbool.h>
#include <stdarg.h>
#include "qemu-common.h"
@@ -206,6 +205,10 @@ static QString *qstring_from_escaped_str(JSONParserContext *ctxt, QObject *token
qstring_append(str, "\b");
ptr++;
break;
+ case 'f':
+ qstring_append(str, "\f");
+ ptr++;
+ break;
case 'n':
qstring_append(str, "\n");
ptr++;
diff --git a/json-streamer.c b/json-streamer.c
index 610ffea..f7e7a68 100644
--- a/json-streamer.c
+++ b/json-streamer.c
@@ -43,11 +43,11 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok
}
dict = qdict_new();
- qdict_put_obj(dict, "type", QOBJECT(qint_from_int(type)));
+ qdict_put(dict, "type", qint_from_int(type));
QINCREF(token);
- qdict_put_obj(dict, "token", QOBJECT(token));
- qdict_put_obj(dict, "x", QOBJECT(qint_from_int(x)));
- qdict_put_obj(dict, "y", QOBJECT(qint_from_int(y)));
+ qdict_put(dict, "token", token);
+ qdict_put(dict, "x", qint_from_int(x));
+ qdict_put(dict, "y", qint_from_int(y));
qlist_append(parser->tokens, dict);
diff --git a/kvm.h b/kvm.h
index a28e7aa..a30529c 100644
--- a/kvm.h
+++ b/kvm.h
@@ -14,7 +14,6 @@
#ifndef QEMU_KVM_H
#define QEMU_KVM_H
-#include <stdbool.h>
#include <errno.h>
#include "config-host.h"
#include "qemu-queue.h"
diff --git a/linux-user/main.c b/linux-user/main.c
index 0f23fc9..403c8d3 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -47,7 +47,7 @@ int have_guest_base;
unsigned long reserved_va;
#endif
-static const char *interp_prefix = CONFIG_QEMU_PREFIX;
+static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
@@ -3271,7 +3271,10 @@ int main(int argc, char **argv, char **envp)
for(i = 0; i < 32; i++) {
env->active_tc.gpr[i] = regs->regs[i];
}
- env->active_tc.PC = regs->cp0_epc;
+ env->active_tc.PC = regs->cp0_epc & ~(target_ulong)1;
+ if (regs->cp0_epc & 1) {
+ env->hflags |= MIPS_HFLAG_M16;
+ }
}
#elif defined(TARGET_SH4)
{
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 8222cb9..e94f1ee 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -208,7 +208,7 @@ _syscall3(int, sys_getdents, uint, fd, struct linux_dirent *, dirp, uint, count)
_syscall3(int, sys_getdents64, uint, fd, struct linux_dirent64 *, dirp, uint, count);
#endif
_syscall2(int, sys_getpriority, int, which, int, who);
-#if defined(TARGET_NR__llseek) && !defined (__x86_64__)
+#if defined(TARGET_NR__llseek) && defined(__NR_llseek)
_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
loff_t *, res, uint, wh);
#endif
@@ -5933,7 +5933,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR__llseek /* Not on alpha */
case TARGET_NR__llseek:
{
-#if defined (__x86_64__)
+#if !defined(__NR_llseek)
ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5));
if (put_user_s64(ret, arg4))
goto efault;
diff --git a/migration-exec.c b/migration-exec.c
index 93bde62..a8813b4 100644
--- a/migration-exec.c
+++ b/migration-exec.c
@@ -20,6 +20,8 @@
#include "sysemu.h"
#include "buffered_file.h"
#include "block.h"
+#include <sys/types.h>
+#include <sys/wait.h>
//#define DEBUG_MIGRATION_EXEC
diff --git a/monitor.c b/monitor.c
index 57f24ff..05a7ed1 100644
--- a/monitor.c
+++ b/monitor.c
@@ -725,20 +725,6 @@ static void do_info_commands(Monitor *mon, QObject **ret_data)
*ret_data = QOBJECT(cmd_list);
}
-#if defined(TARGET_I386)
-static void do_info_hpet_print(Monitor *mon, const QObject *data)
-{
- monitor_printf(mon, "HPET is %s by QEMU\n",
- qdict_get_bool(qobject_to_qdict(data), "enabled") ?
- "enabled" : "disabled");
-}
-
-static void do_info_hpet(Monitor *mon, QObject **ret_data)
-{
- *ret_data = qobject_from_jsonf("{ 'enabled': %i }", !no_hpet);
-}
-#endif
-
static void do_info_uuid_print(Monitor *mon, const QObject *data)
{
monitor_printf(mon, "%s\n", qdict_get_str(qobject_to_qdict(data), "UUID"));
@@ -2407,14 +2393,6 @@ static const mon_cmd_t info_cmds[] = {
.help = "show the active virtual memory mappings",
.mhandler.info = mem_info,
},
- {
- .name = "hpet",
- .args_type = "",
- .params = "",
- .help = "show state of HPET",
- .user_print = do_info_hpet_print,
- .mhandler.info_new = do_info_hpet,
- },
#endif
{
.name = "jit",
diff --git a/nbd.h b/nbd.h
index 5deac29..5a1fbdf 100644
--- a/nbd.h
+++ b/nbd.h
@@ -20,7 +20,6 @@
#define NBD_H
#include <sys/types.h>
-#include <stdbool.h>
#include <qemu-common.h>
#include "block_int.h"
diff --git a/net.c b/net.c
index efa8b3d..4cb93ed 100644
--- a/net.c
+++ b/net.c
@@ -1106,6 +1106,7 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
for (i = 0; net_client_types[i].type != NULL; i++) {
if (!strcmp(net_client_types[i].type, type)) {
VLANState *vlan = NULL;
+ int ret;
if (qemu_opts_validate(opts, &net_client_types[i].desc[0]) == -1) {
return -1;
@@ -1118,14 +1119,16 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
vlan = qemu_find_vlan(qemu_opt_get_number(opts, "vlan", 0), 1);
}
+ ret = -1;
if (net_client_types[i].init) {
- if (net_client_types[i].init(opts, mon, name, vlan) < 0) {
+ ret = net_client_types[i].init(opts, mon, name, vlan);
+ if (ret < 0) {
/* TODO push error reporting into init() methods */
qerror_report(QERR_DEVICE_INIT_FAILED, type);
return -1;
}
}
- return 0;
+ return ret;
}
}
diff --git a/net.h b/net.h
index b83f615..518cf9c 100644
--- a/net.h
+++ b/net.h
@@ -1,7 +1,6 @@
#ifndef QEMU_NET_H
#define QEMU_NET_H
-#include <stdbool.h>
#include "qemu-queue.h"
#include "qemu-common.h"
#include "qdict.h"
diff --git a/os-posix.c b/os-posix.c
new file mode 100644
index 0000000..804e20c
--- /dev/null
+++ b/os-posix.c
@@ -0,0 +1,329 @@
+/*
+ * os-posix.c
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <pwd.h>
+#include <libgen.h>
+
+/* Needed early for CONFIG_BSD etc. */
+#include "config-host.h"
+#include "sysemu.h"
+#include "net/slirp.h"
+#include "qemu-options.h"
+
+#ifdef CONFIG_LINUX
+#include <sys/prctl.h>
+#endif
+
+static struct passwd *user_pwd;
+static const char *chroot_dir;
+static int daemonize;
+static int fds[2];
+
+void os_setup_early_signal_handling(void)
+{
+ struct sigaction act;
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &act, NULL);
+}
+
+static void termsig_handler(int signal)
+{
+ qemu_system_shutdown_request();
+}
+
+static void sigchld_handler(int signal)
+{
+ waitpid(-1, NULL, WNOHANG);
+}
+
+void os_setup_signal_handling(void)
+{
+ struct sigaction act;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = termsig_handler;
+ sigaction(SIGINT, &act, NULL);
+ sigaction(SIGHUP, &act, NULL);
+ sigaction(SIGTERM, &act, NULL);
+
+ act.sa_handler = sigchld_handler;
+ act.sa_flags = SA_NOCLDSTOP;
+ sigaction(SIGCHLD, &act, NULL);
+}
+
+/* Find a likely location for support files using the location of the binary.
+ For installed binaries this will be "$bindir/../share/qemu". When
+ running from the build tree this will be "$bindir/../pc-bios". */
+#define SHARE_SUFFIX "/share/qemu"
+#define BUILD_SUFFIX "/pc-bios"
+char *os_find_datadir(const char *argv0)
+{
+ char *dir;
+ char *p = NULL;
+ char *res;
+ char buf[PATH_MAX];
+ size_t max_len;
+
+#if defined(__linux__)
+ {
+ int len;
+ len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
+ if (len > 0) {
+ buf[len] = 0;
+ p = buf;
+ }
+ }
+#elif defined(__FreeBSD__)
+ {
+ static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+ size_t len = sizeof(buf) - 1;
+
+ *buf = '\0';
+ if (!sysctl(mib, sizeof(mib)/sizeof(*mib), buf, &len, NULL, 0) &&
+ *buf) {
+ buf[sizeof(buf) - 1] = '\0';
+ p = buf;
+ }
+ }
+#endif
+ /* If we don't have any way of figuring out the actual executable
+ location then try argv[0]. */
+ if (!p) {
+ p = realpath(argv0, buf);
+ if (!p) {
+ return NULL;
+ }
+ }
+ dir = dirname(p);
+ dir = dirname(dir);
+
+ max_len = strlen(dir) +
+ MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
+ res = qemu_mallocz(max_len);
+ snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
+ if (access(res, R_OK)) {
+ snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
+ if (access(res, R_OK)) {
+ qemu_free(res);
+ res = NULL;
+ }
+ }
+
+ return res;
+}
+#undef SHARE_SUFFIX
+#undef BUILD_SUFFIX
+
+void os_set_proc_name(const char *s)
+{
+#if defined(PR_SET_NAME)
+ char name[16];
+ if (!s)
+ return;
+ name[sizeof(name) - 1] = 0;
+ strncpy(name, s, sizeof(name));
+ /* Could rewrite argv[0] too, but that's a bit more complicated.
+ This simple way is enough for `top'. */
+ if (prctl(PR_SET_NAME, name)) {
+ perror("unable to change process name");
+ exit(1);
+ }
+#else
+ fprintf(stderr, "Change of process name not supported by your OS\n");
+ exit(1);
+#endif
+}
+
+/*
+ * Parse OS specific command line options.
+ * return 0 if option handled, -1 otherwise
+ */
+void os_parse_cmd_args(int index, const char *optarg)
+{
+ switch (index) {
+#ifdef CONFIG_SLIRP
+ case QEMU_OPTION_smb:
+ if (net_slirp_smb(optarg) < 0)
+ exit(1);
+ break;
+#endif
+ case QEMU_OPTION_runas:
+ user_pwd = getpwnam(optarg);
+ if (!user_pwd) {
+ fprintf(stderr, "User \"%s\" doesn't exist\n", optarg);
+ exit(1);
+ }
+ break;
+ case QEMU_OPTION_chroot:
+ chroot_dir = optarg;
+ break;
+ case QEMU_OPTION_daemonize:
+ daemonize = 1;
+ break;
+ }
+ return;
+}
+
+static void change_process_uid(void)
+{
+ if (user_pwd) {
+ if (setgid(user_pwd->pw_gid) < 0) {
+ fprintf(stderr, "Failed to setgid(%d)\n", user_pwd->pw_gid);
+ exit(1);
+ }
+ if (setuid(user_pwd->pw_uid) < 0) {
+ fprintf(stderr, "Failed to setuid(%d)\n", user_pwd->pw_uid);
+ exit(1);
+ }
+ if (setuid(0) != -1) {
+ fprintf(stderr, "Dropping privileges failed\n");
+ exit(1);
+ }
+ }
+}
+
+static void change_root(void)
+{
+ if (chroot_dir) {
+ if (chroot(chroot_dir) < 0) {
+ fprintf(stderr, "chroot failed\n");
+ exit(1);
+ }
+ if (chdir("/")) {
+ perror("not able to chdir to /");
+ exit(1);
+ }
+ }
+
+}
+
+void os_daemonize(void)
+{
+ if (daemonize) {
+ pid_t pid;
+
+ if (pipe(fds) == -1)
+ exit(1);
+
+ pid = fork();
+ if (pid > 0) {
+ uint8_t status;
+ ssize_t len;
+
+ close(fds[1]);
+
+ again:
+ len = read(fds[0], &status, 1);
+ if (len == -1 && (errno == EINTR))
+ goto again;
+
+ if (len != 1)
+ exit(1);
+ else if (status == 1) {
+ fprintf(stderr, "Could not acquire pidfile: %s\n", strerror(errno));
+ exit(1);
+ } else
+ exit(0);
+ } else if (pid < 0)
+ exit(1);
+
+ close(fds[0]);
+ qemu_set_cloexec(fds[1]);
+
+ setsid();
+
+ pid = fork();
+ if (pid > 0)
+ exit(0);
+ else if (pid < 0)
+ exit(1);
+
+ umask(027);
+
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+ }
+}
+
+void os_setup_post(void)
+{
+ int fd = 0;
+
+ if (daemonize) {
+ uint8_t status = 0;
+ ssize_t len;
+
+ again1:
+ len = write(fds[1], &status, 1);
+ if (len == -1 && (errno == EINTR))
+ goto again1;
+
+ if (len != 1)
+ exit(1);
+
+ if (chdir("/")) {
+ perror("not able to chdir to /");
+ exit(1);
+ }
+ TFR(fd = qemu_open("/dev/null", O_RDWR));
+ if (fd == -1)
+ exit(1);
+ }
+
+ change_root();
+ change_process_uid();
+
+ if (daemonize) {
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+
+ close(fd);
+ }
+}
+
+void os_pidfile_error(void)
+{
+ if (daemonize) {
+ uint8_t status = 1;
+ if (write(fds[1], &status, 1) != 1) {
+ perror("daemonize. Writing to pipe\n");
+ }
+ } else
+ fprintf(stderr, "Could not acquire pid file: %s\n", strerror(errno));
+}
+
+void os_set_line_buffering(void)
+{
+ setvbuf(stdout, NULL, _IOLBF, 0);
+}
diff --git a/os-win32.c b/os-win32.c
new file mode 100644
index 0000000..d98fd77
--- /dev/null
+++ b/os-win32.c
@@ -0,0 +1,221 @@
+/*
+ * os-win32.c
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include <windows.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/time.h>
+#include "config-host.h"
+#include "sysemu.h"
+#include "qemu-options.h"
+
+/***********************************************************/
+/* Polling handling */
+
+typedef struct PollingEntry {
+ PollingFunc *func;
+ void *opaque;
+ struct PollingEntry *next;
+} PollingEntry;
+
+static PollingEntry *first_polling_entry;
+
+int qemu_add_polling_cb(PollingFunc *func, void *opaque)
+{
+ PollingEntry **ppe, *pe;
+ pe = qemu_mallocz(sizeof(PollingEntry));
+ pe->func = func;
+ pe->opaque = opaque;
+ for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
+ *ppe = pe;
+ return 0;
+}
+
+void qemu_del_polling_cb(PollingFunc *func, void *opaque)
+{
+ PollingEntry **ppe, *pe;
+ for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
+ pe = *ppe;
+ if (pe->func == func && pe->opaque == opaque) {
+ *ppe = pe->next;
+ qemu_free(pe);
+ break;
+ }
+ }
+}
+
+/***********************************************************/
+/* Wait objects support */
+typedef struct WaitObjects {
+ int num;
+ HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
+ WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
+ void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
+} WaitObjects;
+
+static WaitObjects wait_objects = {0};
+
+int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+{
+ WaitObjects *w = &wait_objects;
+
+ if (w->num >= MAXIMUM_WAIT_OBJECTS)
+ return -1;
+ w->events[w->num] = handle;
+ w->func[w->num] = func;
+ w->opaque[w->num] = opaque;
+ w->num++;
+ return 0;
+}
+
+void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+{
+ int i, found;
+ WaitObjects *w = &wait_objects;
+
+ found = 0;
+ for (i = 0; i < w->num; i++) {
+ if (w->events[i] == handle)
+ found = 1;
+ if (found) {
+ w->events[i] = w->events[i + 1];
+ w->func[i] = w->func[i + 1];
+ w->opaque[i] = w->opaque[i + 1];
+ }
+ }
+ if (found)
+ w->num--;
+}
+
+void os_host_main_loop_wait(int *timeout)
+{
+ int ret, ret2, i;
+ PollingEntry *pe;
+
+ /* XXX: need to suppress polling by better using win32 events */
+ ret = 0;
+ for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
+ ret |= pe->func(pe->opaque);
+ }
+ if (ret == 0) {
+ int err;
+ WaitObjects *w = &wait_objects;
+
+ ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
+ if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
+ if (w->func[ret - WAIT_OBJECT_0])
+ w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
+
+ /* Check for additional signaled events */
+ for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
+
+ /* Check if event is signaled */
+ ret2 = WaitForSingleObject(w->events[i], 0);
+ if(ret2 == WAIT_OBJECT_0) {
+ if (w->func[i])
+ w->func[i](w->opaque[i]);
+ } else if (ret2 == WAIT_TIMEOUT) {
+ } else {
+ err = GetLastError();
+ fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
+ }
+ }
+ } else if (ret == WAIT_TIMEOUT) {
+ } else {
+ err = GetLastError();
+ fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
+ }
+ }
+
+ *timeout = 0;
+}
+
+static BOOL WINAPI qemu_ctrl_handler(DWORD type)
+{
+ exit(STATUS_CONTROL_C_EXIT);
+ return TRUE;
+}
+
+void os_setup_early_signal_handling(void)
+{
+ /* Note: cpu_interrupt() is currently not SMP safe, so we force
+ QEMU to run on a single CPU */
+ HANDLE h;
+ DWORD mask, smask;
+ int i;
+
+ SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE);
+
+ h = GetCurrentProcess();
+ if (GetProcessAffinityMask(h, &mask, &smask)) {
+ for(i = 0; i < 32; i++) {
+ if (mask & (1 << i))
+ break;
+ }
+ if (i != 32) {
+ mask = 1 << i;
+ SetProcessAffinityMask(h, mask);
+ }
+ }
+}
+
+/* Look for support files in the same directory as the executable. */
+char *os_find_datadir(const char *argv0)
+{
+ char *p;
+ char buf[MAX_PATH];
+ DWORD len;
+
+ len = GetModuleFileName(NULL, buf, sizeof(buf) - 1);
+ if (len == 0) {
+ return NULL;
+ }
+
+ buf[len] = 0;
+ p = buf + len - 1;
+ while (p != buf && *p != '\\')
+ p--;
+ *p = 0;
+ if (access(buf, R_OK) == 0) {
+ return qemu_strdup(buf);
+ }
+ return NULL;
+}
+
+/*
+ * Parse OS specific command line options.
+ * return 0 if option handled, -1 otherwise
+ */
+void os_parse_cmd_args(int index, const char *optarg)
+{
+ return;
+}
+
+void os_pidfile_error(void)
+{
+ fprintf(stderr, "Could not acquire pid file: %s\n", strerror(errno));
+}
diff --git a/pc-bios/optionrom/linuxboot.S b/pc-bios/optionrom/linuxboot.S
index 8aebe51..c109363 100644
--- a/pc-bios/optionrom/linuxboot.S
+++ b/pc-bios/optionrom/linuxboot.S
@@ -106,10 +106,10 @@ copy_kernel:
/* We're now running in 16-bit CS, but 32-bit ES! */
/* Load kernel and initrd */
- read_fw_blob(FW_CFG_KERNEL)
- read_fw_blob(FW_CFG_INITRD)
- read_fw_blob(FW_CFG_CMDLINE)
- read_fw_blob(FW_CFG_SETUP)
+ read_fw_blob_addr32(FW_CFG_KERNEL)
+ read_fw_blob_addr32(FW_CFG_INITRD)
+ read_fw_blob_addr32(FW_CFG_CMDLINE)
+ read_fw_blob_addr32(FW_CFG_SETUP)
/* And now jump into Linux! */
mov $0, %eax
diff --git a/pc-bios/optionrom/optionrom.h b/pc-bios/optionrom/optionrom.h
index 4dcb906..fbdd48a 100644
--- a/pc-bios/optionrom/optionrom.h
+++ b/pc-bios/optionrom/optionrom.h
@@ -50,13 +50,7 @@
bswap %eax
.endm
-/*
- * Read a blob from the fw_cfg device.
- * Requires _ADDR, _SIZE and _DATA values for the parameter.
- *
- * Clobbers: %eax, %edx, %es, %ecx, %edi
- */
-#define read_fw_blob(var) \
+#define read_fw_blob_pre(var) \
read_fw var ## _ADDR; \
mov %eax, %edi; \
read_fw var ## _SIZE; \
@@ -65,10 +59,32 @@
mov $BIOS_CFG_IOPORT_CFG, %edx; \
outw %ax, (%dx); \
mov $BIOS_CFG_IOPORT_DATA, %dx; \
- cld; \
+ cld
+
+/*
+ * Read a blob from the fw_cfg device.
+ * Requires _ADDR, _SIZE and _DATA values for the parameter.
+ *
+ * Clobbers: %eax, %edx, %es, %ecx, %edi
+ */
+#define read_fw_blob(var) \
+ read_fw_blob_pre(var); \
/* old as(1) doesn't like this insn so emit the bytes instead: \
rep insb (%dx), %es:(%edi); \
*/ \
+ .dc.b 0xf3,0x6c
+
+/*
+ * Read a blob from the fw_cfg device in forced addr32 mode.
+ * Requires _ADDR, _SIZE and _DATA values for the parameter.
+ *
+ * Clobbers: %eax, %edx, %es, %ecx, %edi
+ */
+#define read_fw_blob_addr32(var) \
+ read_fw_blob_pre(var); \
+ /* old as(1) doesn't like this insn so emit the bytes instead: \
+ addr32 rep insb (%dx), %es:(%edi); \
+ */ \
.dc.b 0x67,0xf3,0x6c
#define OPTION_ROM_START \
diff --git a/qemu-common.h b/qemu-common.h
index a4888e5..d133f35 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -26,6 +26,7 @@ typedef struct QEMUBH QEMUBH;
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <string.h>
#include <strings.h>
#include <inttypes.h>
diff --git a/qemu-monitor.hx b/qemu-monitor.hx
index f6a94f2..9f62b94 100644
--- a/qemu-monitor.hx
+++ b/qemu-monitor.hx
@@ -2144,27 +2144,6 @@ show the active virtual memory mappings (i386 only)
ETEXI
STEXI
-@item info hpet
-show state of HPET (i386 only)
-ETEXI
-SQMP
-query-hpet
-----------
-
-Show HPET state.
-
-Return a json-object with the following information:
-
-- "enabled": true if hpet if enabled, false otherwise (json-bool)
-
-Example:
-
--> { "execute": "query-hpet" }
-<- { "return": { "enabled": true } }
-
-EQMP
-
-STEXI
@item info jit
show dynamic compiler info
@item info kvm
diff --git a/qemu-options.h b/qemu-options.h
new file mode 100644
index 0000000..c96f994
--- /dev/null
+++ b/qemu-options.h
@@ -0,0 +1,41 @@
+/*
+ * qemu-options.h
+ *
+ * Defines needed for command line argument processing.
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010 Jes Sorensen <Jes.Sorensen@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef _QEMU_OPTIONS_H_
+#define _QEMU_OPTIONS_H_
+
+enum {
+#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask) \
+ opt_enum,
+#define DEFHEADING(text)
+#include "qemu-options.def"
+#undef DEF
+#undef DEFHEADING
+#undef GEN_DOCS
+};
+
+#endif
diff --git a/qemu-os-posix.h b/qemu-os-posix.h
new file mode 100644
index 0000000..ed5c058
--- /dev/null
+++ b/qemu-os-posix.h
@@ -0,0 +1,39 @@
+/*
+ * posix specific declarations
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010 Jes Sorensen <Jes.Sorensen@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_OS_POSIX_H
+#define QEMU_OS_POSIX_H
+
+static inline void os_host_main_loop_wait(int *timeout)
+{
+}
+
+void os_set_line_buffering(void);
+void os_set_proc_name(const char *s);
+void os_setup_signal_handling(void);
+void os_daemonize(void);
+void os_setup_post(void);
+
+#endif
diff --git a/qemu-os-win32.h b/qemu-os-win32.h
new file mode 100644
index 0000000..6323f7f
--- /dev/null
+++ b/qemu-os-win32.h
@@ -0,0 +1,52 @@
+/*
+ * win32 specific declarations
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010 Jes Sorensen <Jes.Sorensen@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_OS_WIN32_H
+#define QEMU_OS_WIN32_H
+
+/* Polling handling */
+
+/* return TRUE if no sleep should be done afterwards */
+typedef int PollingFunc(void *opaque);
+
+int qemu_add_polling_cb(PollingFunc *func, void *opaque);
+void qemu_del_polling_cb(PollingFunc *func, void *opaque);
+
+/* Wait objects handling */
+typedef void WaitObjectFunc(void *opaque);
+
+int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
+void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
+
+void os_host_main_loop_wait(int *timeout);
+
+static inline void os_setup_signal_handling(void) {}
+static inline void os_daemonize(void) {}
+static inline void os_setup_post(void) {}
+/* Win32 doesn't support line-buffering and requires size >= 2 */
+static inline void os_set_line_buffering(void) {}
+static inline void os_set_proc_name(const char *dummy) {}
+
+#endif
diff --git a/qjson.c b/qjson.c
index 483c667..e4ee433 100644
--- a/qjson.c
+++ b/qjson.c
@@ -158,6 +158,9 @@ static void to_json(const QObject *obj, QString *str)
case '\b':
qstring_append(str, "\\b");
break;
+ case '\f':
+ qstring_append(str, "\\f");
+ break;
case '\n':
qstring_append(str, "\\n");
break;
diff --git a/s390-dis.c b/s390-dis.c
index 86dd84f..8abcdf0 100644
--- a/s390-dis.c
+++ b/s390-dis.c
@@ -1,3 +1,4 @@
+/* opcodes/s390-dis.c revision 1.12 */
/* s390-dis.c -- Disassemble S390 instructions
Copyright 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
@@ -15,11 +16,14 @@
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, see <http://www.gnu.org/licenses/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
-#include <stdio.h>
+#include "qemu-common.h"
#include "dis-asm.h"
+/* include/opcode/s390.h revision 1.9 */
/* s390.h -- Header file for S390 opcode table
Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
@@ -37,7 +41,9 @@
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, see <http://www.gnu.org/licenses/>. */
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
#ifndef S390_H
#define S390_H
@@ -57,7 +63,8 @@ enum s390_opcode_cpu_val
S390_OPCODE_Z900,
S390_OPCODE_Z990,
S390_OPCODE_Z9_109,
- S390_OPCODE_Z9_EC
+ S390_OPCODE_Z9_EC,
+ S390_OPCODE_Z10
};
/* The opcode table is an array of struct s390_opcode. */
@@ -95,12 +102,13 @@ struct s390_opcode
/* The table itself is sorted by major opcode number, and is otherwise
in the order in which the disassembler should consider
instructions. */
-extern const struct s390_opcode s390_opcodes[];
-extern const int s390_num_opcodes;
+/* QEMU: Mark these static. */
+static const struct s390_opcode s390_opcodes[];
+static const int s390_num_opcodes;
/* A opcode format table for the .insn pseudo mnemonic. */
-extern const struct s390_opcode s390_opformats[];
-extern const int s390_num_opformats;
+static const struct s390_opcode s390_opformats[];
+static const int s390_num_opformats;
/* Values defined for the flags field of a struct powerpc_opcode. */
@@ -121,7 +129,7 @@ struct s390_operand
/* Elements in the table are retrieved by indexing with values from
the operands field of the powerpc_opcodes table. */
-extern const struct s390_operand s390_operands[];
+static const struct s390_operand s390_operands[];
/* Values defined for the flags field of a struct s390_operand. */
@@ -164,12 +172,38 @@ extern const struct s390_operand s390_operands[];
the instruction may be optional. */
#define S390_OPERAND_OPTIONAL 0x400
- #endif /* S390_H */
+/* QEMU-ADD */
+/* ??? Not quite the format the assembler takes, but easy to implement
+ without recourse to the table generator. */
+#define S390_OPERAND_CCODE 0x800
+
+static const char s390_ccode_name[16][4] = {
+ "n", /* 0000 */
+ "o", /* 0001 */
+ "h", /* 0010 */
+ "nle", /* 0011 */
+ "l", /* 0100 */
+ "nhe", /* 0101 */
+ "lh", /* 0110 */
+ "ne", /* 0111 */
+ "e", /* 1000 */
+ "nlh", /* 1001 */
+ "he", /* 1010 */
+ "nl", /* 1011 */
+ "le", /* 1100 */
+ "nh", /* 1101 */
+ "no", /* 1110 */
+ "a" /* 1111 */
+};
+/* QEMU-END */
+#endif /* S390_H */
static int init_flag = 0;
static int opc_index[256];
-static int current_arch_mask = 0;
+
+/* QEMU: We've disabled the architecture check below. */
+/* static int current_arch_mask = 0; */
/* Set up index table for first opcode byte. */
@@ -188,17 +222,21 @@ init_disasm (struct disassemble_info *info)
(opcode[1].opcode[0] == opcode->opcode[0]))
opcode++;
}
-// switch (info->mach)
-// {
-// case bfd_mach_s390_31:
+
+#ifdef QEMU_DISABLE
+ switch (info->mach)
+ {
+ case bfd_mach_s390_31:
current_arch_mask = 1 << S390_OPCODE_ESA;
-// break;
-// case bfd_mach_s390_64:
-// current_arch_mask = 1 << S390_OPCODE_ZARCH;
-// break;
-// default:
-// abort ();
-// }
+ break;
+ case bfd_mach_s390_64:
+ current_arch_mask = 1 << S390_OPCODE_ZARCH;
+ break;
+ default:
+ abort ();
+ }
+#endif /* QEMU_DISABLE */
+
init_flag = 1;
}
@@ -297,9 +335,12 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
const struct s390_operand *operand;
const unsigned char *opindex;
+#ifdef QEMU_DISABLE
/* Check architecture. */
if (!(opcode->modes & current_arch_mask))
continue;
+#endif /* QEMU_DISABLE */
+
/* Check signature of the opcode. */
if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1]
|| (buffer[2] & opcode->mask[2]) != opcode->opcode[2]
@@ -309,13 +350,16 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
continue;
/* The instruction is valid. */
- if (opcode->operands[0] != 0)
- (*info->fprintf_func) (info->stream, "%s\t", opcode->name);
- else
- (*info->fprintf_func) (info->stream, "%s", opcode->name);
+/* QEMU-MOD */
+ (*info->fprintf_func) (info->stream, "%s", opcode->name);
+
+ if (s390_operands[opcode->operands[0]].flags & S390_OPERAND_CCODE)
+ separator = 0;
+ else
+ separator = '\t';
+/* QEMU-END */
/* Extract the operands. */
- separator = 0;
for (opindex = opcode->operands; *opindex != 0; opindex++)
{
unsigned int value;
@@ -347,6 +391,15 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
(*info->print_address_func) (memaddr + (int) value, info);
else if (operand->flags & S390_OPERAND_SIGNED)
(*info->fprintf_func) (info->stream, "%i", (int) value);
+/* QEMU-ADD */
+ else if (operand->flags & S390_OPERAND_CCODE)
+ {
+ (*info->fprintf_func) (info->stream, "%s",
+ s390_ccode_name[(int) value]);
+ separator = '\t';
+ continue;
+ }
+/* QEMU-END */
else
(*info->fprintf_func) (info->stream, "%u", value);
@@ -392,6 +445,8 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
return 1;
}
}
+
+/* opcodes/s390-opc.c revision 1.16 */
/* s390-opc.c -- S390 opcode list
Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
@@ -409,9 +464,9 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
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, see <http://www.gnu.org/licenses/>. */
-
-#include <stdio.h>
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
/* This file holds the S390 opcode table. The opcode table
includes almost all of the extended instruction mnemonics. This
@@ -427,7 +482,7 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
/* The operands table.
The fields are bits, shift, insert, extract, flags. */
-const struct s390_operand s390_operands[] =
+static const struct s390_operand s390_operands[] =
{
#define UNUSED 0
{ 0, 0, 0 }, /* Indicates the end of the operand list */
@@ -525,8 +580,16 @@ const struct s390_operand s390_operands[] =
#define M_16 42 /* 4 bit optional mask starting at 16 */
{ 4, 16, S390_OPERAND_OPTIONAL },
#define RO_28 43 /* optional GPR starting at position 28 */
- { 4, 28, (S390_OPERAND_GPR | S390_OPERAND_OPTIONAL) }
-
+ { 4, 28, (S390_OPERAND_GPR | S390_OPERAND_OPTIONAL) },
+
+/* QEMU-ADD: */
+#define M4_12 44 /* 4-bit condition-code starting at 12 */
+ { 4, 12, S390_OPERAND_CCODE },
+#define M4_32 45 /* 4-bit condition-code starting at 32 */
+ { 4, 32, S390_OPERAND_CCODE },
+#define I8_32 46 /* 8 bit signed value starting at 32 */
+ { 8, 32, S390_OPERAND_SIGNED },
+/* QEMU-END */
};
@@ -737,9 +800,17 @@ const struct s390_operand s390_operands[] =
#define MASK_S_RD { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
#define MASK_SSF_RRDRD { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+/* QEMU-ADD: */
+#define INSTR_RIE_MRRP 6, { M4_32,R_8,R_12,J16_16,0,0 } /* e.g. crj */
+#define MASK_RIE_MRRP { 0xff, 0x00, 0x00, 0x00, 0x0f, 0xff }
+
+#define INSTR_RIE_MRIP 6, { M4_12,R_8,I8_32,J16_16,0,0 } /* e.g. cij */
+#define MASK_RIE_MRIP { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+/* QEMU-END */
+
/* The opcode formats table (blueprints for .insn pseudo mnemonic). */
-const struct s390_opcode s390_opformats[] =
+static const struct s390_opcode s390_opformats[] =
{
{ "e", OP8(0x00LL), MASK_E, INSTR_E, 3, 0 },
{ "ri", OP8(0x00LL), MASK_RI_RI, INSTR_RI_RI, 3, 0 },
@@ -765,9 +836,10 @@ const struct s390_opcode s390_opformats[] =
{ "ssf", OP8(0x00LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD,3, 0 },
};
-const int s390_num_opformats =
+static const int s390_num_opformats =
sizeof (s390_opformats) / sizeof (s390_opformats[0]);
+/* include "s390-opc.tab" generated from opcodes/s390-opc.txt rev 1.17 */
/* The opcode table. This file was generated by s390-mkopc.
The format of the opcode table is:
@@ -783,7 +855,7 @@ const int s390_num_opformats =
The disassembler reads the table in order and prints the first
instruction which matches. */
-const struct s390_opcode s390_opcodes[] =
+static const struct s390_opcode s390_opcodes[] =
{
{ "dp", OP8(0xfdLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
{ "mp", OP8(0xfcLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
@@ -1073,6 +1145,10 @@ const struct s390_opcode s390_opcodes[] =
{ "agfi", OP16(0xc208LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4},
{ "slfi", OP16(0xc205LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
{ "slgfi", OP16(0xc204LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+/* QEMU-ADD: */
+ { "msfi", OP16(0xc201ll), MASK_RIL_RI, INSTR_RIL_RI, 3, 6},
+ { "msgfi", OP16(0xc200ll), MASK_RIL_RI, INSTR_RIL_RI, 3, 6},
+/* QEMU-END */
{ "jg", OP16(0xc0f4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
{ "jgno", OP16(0xc0e4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
{ "jgnh", OP16(0xc0d4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
@@ -1697,8 +1773,24 @@ const struct s390_opcode s390_opcodes[] =
{ "pfpo", OP16(0x010aLL), MASK_E, INSTR_E, 2, 5},
{ "sckpf", OP16(0x0107LL), MASK_E, INSTR_E, 3, 0},
{ "upt", OP16(0x0102LL), MASK_E, INSTR_E, 3, 0},
- { "pr", OP16(0x0101LL), MASK_E, INSTR_E, 3, 0}
+ { "pr", OP16(0x0101LL), MASK_E, INSTR_E, 3, 0},
+
+/* QEMU-ADD: */
+ { "crj", OP48(0xec0000000076LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
+ { "cgrj", OP48(0xec0000000064LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
+ { "clrj", OP48(0xec0000000077LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
+ { "clgrj", OP48(0xec0000000065LL), MASK_RIE_MRRP, INSTR_RIE_MRRP, 3, 6},
+
+ { "cij", OP48(0xec000000007eLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
+ { "cgij", OP48(0xec000000007cLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
+ { "clij", OP48(0xec000000007fLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
+ { "clgij", OP48(0xec000000007dLL), MASK_RIE_MRIP, INSTR_RIE_MRIP, 3, 6},
+
+ { "lrl", OP16(0xc40dll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
+ { "lgrl", OP16(0xc408ll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
+ { "lgfrl", OP16(0xc40cll), MASK_RIL_RP, INSTR_RIL_RP, 3, 6},
+/* QEMU-END */
};
-const int s390_num_opcodes =
+static const int s390_num_opcodes =
sizeof (s390_opcodes) / sizeof (s390_opcodes[0]);
diff --git a/sysemu.h b/sysemu.h
index 5fa45ed..fbe103b 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -9,6 +9,11 @@
#ifdef _WIN32
#include <windows.h>
+#include "qemu-os-win32.h"
+#endif
+
+#ifdef CONFIG_POSIX
+#include "qemu-os-posix.h"
#endif
/* vl.c */
@@ -71,25 +76,15 @@ int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f);
void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f);
int qemu_loadvm_state(QEMUFile *f);
-#ifdef _WIN32
-/* Polling handling */
-
-/* return TRUE if no sleep should be done afterwards */
-typedef int PollingFunc(void *opaque);
-
-int qemu_add_polling_cb(PollingFunc *func, void *opaque);
-void qemu_del_polling_cb(PollingFunc *func, void *opaque);
-
-/* Wait objects handling */
-typedef void WaitObjectFunc(void *opaque);
-
-int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
-void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
-#endif
-
/* SLIRP */
void do_info_slirp(Monitor *mon);
+/* OS specific functions */
+void os_setup_early_signal_handling(void);
+char *os_find_datadir(const char *argv0);
+void os_parse_cmd_args(int index, const char *optarg);
+void os_pidfile_error(void);
+
typedef enum DisplayType
{
DT_DEFAULT,
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 0eccca5..a28e2ff 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -3854,7 +3854,8 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
tcg_gen_addi_i32(addr, addr, stride);
tmp2 = gen_ld16u(addr, IS_USER(s));
tcg_gen_addi_i32(addr, addr, stride);
- gen_bfi(tmp, tmp, tmp2, 16, 0xffff);
+ tcg_gen_shli_i32(tmp2, tmp2, 16);
+ tcg_gen_or_i32(tmp, tmp, tmp2);
dead_tmp(tmp2);
neon_store_reg(rd, pass, tmp);
} else {
@@ -3875,7 +3876,8 @@ static int disas_neon_ls_insn(CPUState * env, DisasContext *s, uint32_t insn)
if (n == 0) {
tmp2 = tmp;
} else {
- gen_bfi(tmp2, tmp2, tmp, n * 8, 0xff);
+ tcg_gen_shli_i32(tmp, tmp, n * 8);
+ tcg_gen_or_i32(tmp2, tmp2, tmp);
dead_tmp(tmp);
}
}
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index 063a240..a62d57c 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -155,6 +155,8 @@ typedef struct CPUCRISState {
uint32_t lo;
} tlbsets[2][4][16];
+ void *load_info;
+
CPU_COMMON
} CPUCRISState;
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 38c6016..708b0a1 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -2016,7 +2016,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
break;
default:
case 2:
- disp = ldl_code(s->pc);
+ disp = (int32_t)ldl_code(s->pc);
s->pc += 4;
break;
}
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h
index 3316797..ff8c8c8 100644
--- a/target-microblaze/cpu.h
+++ b/target-microblaze/cpu.h
@@ -217,8 +217,7 @@ typedef struct CPUMBState {
#define DRTB_FLAG (1 << 18)
#define D_FLAG (1 << 19) /* Bit in ESR. */
/* TB dependant CPUState. */
-#define IFLAGS_TB_MASK (D_FLAG | IMM_FLAG | DRTI_FLAG \
- | DRTE_FLAG | DRTB_FLAG | MSR_EE_FLAG)
+#define IFLAGS_TB_MASK (D_FLAG | IMM_FLAG | DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)
uint32_t iflags;
struct {
@@ -323,8 +322,8 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
{
*pc = env->sregs[SR_PC];
*cs_base = 0;
- env->iflags |= env->sregs[SR_MSR] & MSR_EE;
- *flags = env->iflags & IFLAGS_TB_MASK;
+ *flags = (env->iflags & IFLAGS_TB_MASK) |
+ (env->sregs[SR_MSR] & (MSR_UM | MSR_VM | MSR_EE));
}
#if !defined(CONFIG_USER_ONLY)
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 7285636..c21b8e4 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -363,6 +363,7 @@ struct CPUMIPSState {
#define CP0C2_SA 0
int32_t CP0_Config3;
#define CP0C3_M 31
+#define CP0C3_ISA_ON_EXC 16
#define CP0C3_DSPP 10
#define CP0C3_LPA 7
#define CP0C3_VEIC 6
diff --git a/target-mips/helper.c b/target-mips/helper.c
index 8102f03..ea221ab 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -385,6 +385,18 @@ static target_ulong exception_resume_pc (CPUState *env)
return bad_pc;
}
+
+static void set_hflags_for_handler (CPUState *env)
+{
+ /* Exception handlers are entered in 32-bit mode. */
+ env->hflags &= ~(MIPS_HFLAG_M16);
+ /* ...except that microMIPS lets you choose. */
+ if (env->insn_flags & ASE_MICROMIPS) {
+ env->hflags |= (!!(env->CP0_Config3
+ & (1 << CP0C3_ISA_ON_EXC))
+ << MIPS_HFLAG_M16_SHIFT);
+ }
+}
#endif
void do_interrupt (CPUState *env)
@@ -440,8 +452,7 @@ void do_interrupt (CPUState *env)
if (!(env->CP0_Status & (1 << CP0St_EXL)))
env->CP0_Cause &= ~(1 << CP0Ca_BD);
env->active_tc.PC = (int32_t)0xBFC00480;
- /* Exception handlers are entered in 32-bit mode. */
- env->hflags &= ~(MIPS_HFLAG_M16);
+ set_hflags_for_handler(env);
break;
case EXCP_RESET:
cpu_reset(env);
@@ -461,8 +472,7 @@ void do_interrupt (CPUState *env)
if (!(env->CP0_Status & (1 << CP0St_EXL)))
env->CP0_Cause &= ~(1 << CP0Ca_BD);
env->active_tc.PC = (int32_t)0xBFC00000;
- /* Exception handlers are entered in 32-bit mode. */
- env->hflags &= ~(MIPS_HFLAG_M16);
+ set_hflags_for_handler(env);
break;
case EXCP_EXT_INTERRUPT:
cause = 0;
@@ -581,8 +591,7 @@ void do_interrupt (CPUState *env)
env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
}
env->active_tc.PC += offset;
- /* Exception handlers are entered in 32-bit mode. */
- env->hflags &= ~(MIPS_HFLAG_M16);
+ set_hflags_for_handler(env);
env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
break;
default:
diff --git a/target-mips/helper.h b/target-mips/helper.h
index ab47b1a..a6ba75d 100644
--- a/target-mips/helper.h
+++ b/target-mips/helper.h
@@ -160,6 +160,15 @@ DEF_HELPER_1(emt, tl, tl)
DEF_HELPER_1(dvpe, tl, tl)
DEF_HELPER_1(evpe, tl, tl)
#endif /* !CONFIG_USER_ONLY */
+
+/* microMIPS functions */
+DEF_HELPER_3(lwm, void, tl, tl, i32);
+DEF_HELPER_3(swm, void, tl, tl, i32);
+#ifdef TARGET_MIPS64
+DEF_HELPER_3(ldm, void, tl, tl, i32);
+DEF_HELPER_3(sdm, void, tl, tl, i32);
+#endif
+
DEF_HELPER_2(fork, void, tl, tl)
DEF_HELPER_1(yield, tl, tl)
diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h
index c57de02..a7f4697 100644
--- a/target-mips/mips-defs.h
+++ b/target-mips/mips-defs.h
@@ -38,6 +38,7 @@
#define ASE_DSPR2 0x00010000
#define ASE_MT 0x00020000
#define ASE_SMARTMIPS 0x00040000
+#define ASE_MICROMIPS 0x00080000
/* Chip specific instructions. */
#define INSN_VR54XX 0x80000000
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 2bfdd50..d09d6ed54 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -565,6 +565,142 @@ void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx)
}
#endif /* TARGET_MIPS64 */
+static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
+
+void helper_lwm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef ldfun
+#define ldfun ldl_raw
+#else
+ uint32_t (*ldfun)(target_ulong);
+
+ switch (mem_idx)
+ {
+ case 0: ldfun = ldl_kernel; break;
+ case 1: ldfun = ldl_super; break;
+ default:
+ case 2: ldfun = ldl_user; break;
+ }
+#endif
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ env->active_tc.gpr[multiple_regs[i]] = (target_long) ldfun(addr);
+ addr += 4;
+ }
+ }
+
+ if (do_r31) {
+ env->active_tc.gpr[31] = (target_long) ldfun(addr);
+ }
+}
+
+void helper_swm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef stfun
+#define stfun stl_raw
+#else
+ void (*stfun)(target_ulong, uint32_t);
+
+ switch (mem_idx)
+ {
+ case 0: stfun = stl_kernel; break;
+ case 1: stfun = stl_super; break;
+ default:
+ case 2: stfun = stl_user; break;
+ }
+#endif
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
+ addr += 4;
+ }
+ }
+
+ if (do_r31) {
+ stfun(addr, env->active_tc.gpr[31]);
+ }
+}
+
+#if defined(TARGET_MIPS64)
+void helper_ldm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef ldfun
+#define ldfun ldq_raw
+#else
+ uint64_t (*ldfun)(target_ulong);
+
+ switch (mem_idx)
+ {
+ case 0: ldfun = ldq_kernel; break;
+ case 1: ldfun = ldq_super; break;
+ default:
+ case 2: ldfun = ldq_user; break;
+ }
+#endif
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ env->active_tc.gpr[multiple_regs[i]] = ldfun(addr);
+ addr += 8;
+ }
+ }
+
+ if (do_r31) {
+ env->active_tc.gpr[31] = ldfun(addr);
+ }
+}
+
+void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef stfun
+#define stfun stq_raw
+#else
+ void (*stfun)(target_ulong, uint64_t);
+
+ switch (mem_idx)
+ {
+ case 0: stfun = stq_kernel; break;
+ case 1: stfun = stq_super; break;
+ default:
+ case 2: stfun = stq_user; break;
+ }
+#endif
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
+ addr += 8;
+ }
+ }
+
+ if (do_r31) {
+ stfun(addr, env->active_tc.gpr[31]);
+ }
+}
+#endif
+
#ifndef CONFIG_USER_ONLY
/* CP0 helpers */
target_ulong helper_mfc0_mvpcontrol (void)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index c95ecb1..d43d72d 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -4,7 +4,7 @@
* Copyright (c) 2004-2005 Jocelyn Mayer
* Copyright (c) 2006 Marius Groeger (FPU operations)
* Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
- * Copyright (c) 2009 CodeSourcery (MIPS16 support)
+ * Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -68,6 +68,7 @@ enum {
/* Jump and branches */
OPC_J = (0x02 << 26),
OPC_JAL = (0x03 << 26),
+ OPC_JALS = OPC_JAL | 0x5,
OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */
OPC_BEQL = (0x14 << 26),
OPC_BNE = (0x05 << 26),
@@ -77,6 +78,7 @@ enum {
OPC_BGTZ = (0x07 << 26),
OPC_BGTZL = (0x17 << 26),
OPC_JALX = (0x1D << 26), /* MIPS 16 only */
+ OPC_JALXS = OPC_JALX | 0x5,
/* Load and stores */
OPC_LDL = (0x1A << 26),
OPC_LDR = (0x1B << 26),
@@ -177,6 +179,7 @@ enum {
OPC_JR = 0x08 | OPC_SPECIAL, /* Also JR.HB */
OPC_JALR = 0x09 | OPC_SPECIAL, /* Also JALR.HB */
OPC_JALRC = OPC_JALR | (0x5 << 6),
+ OPC_JALRS = 0x10 | OPC_SPECIAL | (0x5 << 6),
/* Traps */
OPC_TGE = 0x30 | OPC_SPECIAL,
OPC_TGEU = 0x31 | OPC_SPECIAL,
@@ -240,8 +243,10 @@ enum {
OPC_BGEZ = (0x01 << 16) | OPC_REGIMM,
OPC_BGEZL = (0x03 << 16) | OPC_REGIMM,
OPC_BLTZAL = (0x10 << 16) | OPC_REGIMM,
+ OPC_BLTZALS = OPC_BLTZAL | 0x5, /* microMIPS */
OPC_BLTZALL = (0x12 << 16) | OPC_REGIMM,
OPC_BGEZAL = (0x11 << 16) | OPC_REGIMM,
+ OPC_BGEZALS = OPC_BGEZAL | 0x5, /* microMIPS */
OPC_BGEZALL = (0x13 << 16) | OPC_REGIMM,
OPC_TGEI = (0x08 << 16) | OPC_REGIMM,
OPC_TGEIU = (0x09 << 16) | OPC_REGIMM,
@@ -354,6 +359,19 @@ enum {
/* Coprocessor 1 (rs field) */
#define MASK_CP1(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21))
+/* Values for the fmt field in FP instructions */
+enum {
+ /* 0 - 15 are reserved */
+ FMT_S = 16, /* single fp */
+ FMT_D = 17, /* double fp */
+ FMT_E = 18, /* extended fp */
+ FMT_Q = 19, /* quad fp */
+ FMT_W = 20, /* 32-bit fixed */
+ FMT_L = 21, /* 64-bit fixed */
+ FMT_PS = 22, /* paired single fp */
+ /* 23 - 31 are reserved */
+};
+
enum {
OPC_MFC1 = (0x00 << 21) | OPC_CP1,
OPC_DMFC1 = (0x01 << 21) | OPC_CP1,
@@ -366,13 +384,13 @@ enum {
OPC_BC1 = (0x08 << 21) | OPC_CP1, /* bc */
OPC_BC1ANY2 = (0x09 << 21) | OPC_CP1,
OPC_BC1ANY4 = (0x0A << 21) | OPC_CP1,
- OPC_S_FMT = (0x10 << 21) | OPC_CP1, /* 16: fmt=single fp */
- OPC_D_FMT = (0x11 << 21) | OPC_CP1, /* 17: fmt=double fp */
- OPC_E_FMT = (0x12 << 21) | OPC_CP1, /* 18: fmt=extended fp */
- OPC_Q_FMT = (0x13 << 21) | OPC_CP1, /* 19: fmt=quad fp */
- OPC_W_FMT = (0x14 << 21) | OPC_CP1, /* 20: fmt=32bit fixed */
- OPC_L_FMT = (0x15 << 21) | OPC_CP1, /* 21: fmt=64bit fixed */
- OPC_PS_FMT = (0x16 << 21) | OPC_CP1, /* 22: fmt=paired single fp */
+ OPC_S_FMT = (FMT_S << 21) | OPC_CP1,
+ OPC_D_FMT = (FMT_D << 21) | OPC_CP1,
+ OPC_E_FMT = (FMT_E << 21) | OPC_CP1,
+ OPC_Q_FMT = (FMT_Q << 21) | OPC_CP1,
+ OPC_W_FMT = (FMT_W << 21) | OPC_CP1,
+ OPC_L_FMT = (FMT_L << 21) | OPC_CP1,
+ OPC_PS_FMT = (FMT_PS << 21) | OPC_CP1,
};
#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F)
@@ -663,39 +681,6 @@ static inline int get_fp_bit (int cc)
return 23;
}
-#define FOP_CONDS(type, fmt, bits) \
-static inline void gen_cmp ## type ## _ ## fmt(int n, TCGv_i##bits a, \
- TCGv_i##bits b, int cc) \
-{ \
- switch (n) { \
- case 0: gen_helper_2i(cmp ## type ## _ ## fmt ## _f, a, b, cc); break;\
- case 1: gen_helper_2i(cmp ## type ## _ ## fmt ## _un, a, b, cc); break;\
- case 2: gen_helper_2i(cmp ## type ## _ ## fmt ## _eq, a, b, cc); break;\
- case 3: gen_helper_2i(cmp ## type ## _ ## fmt ## _ueq, a, b, cc); break;\
- case 4: gen_helper_2i(cmp ## type ## _ ## fmt ## _olt, a, b, cc); break;\
- case 5: gen_helper_2i(cmp ## type ## _ ## fmt ## _ult, a, b, cc); break;\
- case 6: gen_helper_2i(cmp ## type ## _ ## fmt ## _ole, a, b, cc); break;\
- case 7: gen_helper_2i(cmp ## type ## _ ## fmt ## _ule, a, b, cc); break;\
- case 8: gen_helper_2i(cmp ## type ## _ ## fmt ## _sf, a, b, cc); break;\
- case 9: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngle, a, b, cc); break;\
- case 10: gen_helper_2i(cmp ## type ## _ ## fmt ## _seq, a, b, cc); break;\
- case 11: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngl, a, b, cc); break;\
- case 12: gen_helper_2i(cmp ## type ## _ ## fmt ## _lt, a, b, cc); break;\
- case 13: gen_helper_2i(cmp ## type ## _ ## fmt ## _nge, a, b, cc); break;\
- case 14: gen_helper_2i(cmp ## type ## _ ## fmt ## _le, a, b, cc); break;\
- case 15: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngt, a, b, cc); break;\
- default: abort(); \
- } \
-}
-
-FOP_CONDS(, d, 64)
-FOP_CONDS(abs, d, 64)
-FOP_CONDS(, s, 32)
-FOP_CONDS(abs, s, 32)
-FOP_CONDS(, ps, 64)
-FOP_CONDS(abs, ps, 64)
-#undef FOP_CONDS
-
/* Tests */
static inline void gen_save_pc(target_ulong pc)
{
@@ -836,6 +821,69 @@ static inline void check_mips_64(DisasContext *ctx)
generate_exception(ctx, EXCP_RI);
}
+/* Define small wrappers for gen_load_fpr* so that we have a uniform
+ calling interface for 32 and 64-bit FPRs. No sense in changing
+ all callers for gen_load_fpr32 when we need the CTX parameter for
+ this one use. */
+#define gen_ldcmp_fpr32(ctx, x, y) gen_load_fpr32(x, y)
+#define gen_ldcmp_fpr64(ctx, x, y) gen_load_fpr64(ctx, x, y)
+#define FOP_CONDS(type, abs, fmt, ifmt, bits) \
+static inline void gen_cmp ## type ## _ ## fmt(DisasContext *ctx, int n, \
+ int ft, int fs, int cc) \
+{ \
+ TCGv_i##bits fp0 = tcg_temp_new_i##bits (); \
+ TCGv_i##bits fp1 = tcg_temp_new_i##bits (); \
+ switch (ifmt) { \
+ case FMT_PS: \
+ check_cp1_64bitmode(ctx); \
+ break; \
+ case FMT_D: \
+ if (abs) { \
+ check_cop1x(ctx); \
+ } \
+ check_cp1_registers(ctx, fs | ft); \
+ break; \
+ case FMT_S: \
+ if (abs) { \
+ check_cop1x(ctx); \
+ } \
+ break; \
+ } \
+ gen_ldcmp_fpr##bits (ctx, fp0, fs); \
+ gen_ldcmp_fpr##bits (ctx, fp1, ft); \
+ switch (n) { \
+ case 0: gen_helper_2i(cmp ## type ## _ ## fmt ## _f, fp0, fp1, cc); break;\
+ case 1: gen_helper_2i(cmp ## type ## _ ## fmt ## _un, fp0, fp1, cc); break;\
+ case 2: gen_helper_2i(cmp ## type ## _ ## fmt ## _eq, fp0, fp1, cc); break;\
+ case 3: gen_helper_2i(cmp ## type ## _ ## fmt ## _ueq, fp0, fp1, cc); break;\
+ case 4: gen_helper_2i(cmp ## type ## _ ## fmt ## _olt, fp0, fp1, cc); break;\
+ case 5: gen_helper_2i(cmp ## type ## _ ## fmt ## _ult, fp0, fp1, cc); break;\
+ case 6: gen_helper_2i(cmp ## type ## _ ## fmt ## _ole, fp0, fp1, cc); break;\
+ case 7: gen_helper_2i(cmp ## type ## _ ## fmt ## _ule, fp0, fp1, cc); break;\
+ case 8: gen_helper_2i(cmp ## type ## _ ## fmt ## _sf, fp0, fp1, cc); break;\
+ case 9: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngle, fp0, fp1, cc); break;\
+ case 10: gen_helper_2i(cmp ## type ## _ ## fmt ## _seq, fp0, fp1, cc); break;\
+ case 11: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngl, fp0, fp1, cc); break;\
+ case 12: gen_helper_2i(cmp ## type ## _ ## fmt ## _lt, fp0, fp1, cc); break;\
+ case 13: gen_helper_2i(cmp ## type ## _ ## fmt ## _nge, fp0, fp1, cc); break;\
+ case 14: gen_helper_2i(cmp ## type ## _ ## fmt ## _le, fp0, fp1, cc); break;\
+ case 15: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngt, fp0, fp1, cc); break;\
+ default: abort(); \
+ } \
+ tcg_temp_free_i##bits (fp0); \
+ tcg_temp_free_i##bits (fp1); \
+}
+
+FOP_CONDS(, 0, d, FMT_D, 64)
+FOP_CONDS(abs, 1, d, FMT_D, 64)
+FOP_CONDS(, 0, s, FMT_S, 32)
+FOP_CONDS(abs, 1, s, FMT_S, 32)
+FOP_CONDS(, 0, ps, FMT_PS, 64)
+FOP_CONDS(abs, 1, ps, FMT_PS, 64)
+#undef FOP_CONDS
+#undef gen_ldcmp_fpr32
+#undef gen_ldcmp_fpr64
+
/* load/store instructions. */
#define OP_LD(insn,fname) \
static inline void op_ldst_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \
@@ -1220,6 +1268,17 @@ static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
tcg_temp_free(t0);
}
+static void gen_cop1_ldst(CPUState *env, DisasContext *ctx,
+ uint32_t op, int rt, int rs, int16_t imm)
+{
+ if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+ check_cp1_enabled(ctx);
+ gen_flt_ldst(ctx, op, rt, rs, imm);
+ } else {
+ generate_exception_err(ctx, EXCP_CpU, 1);
+ }
+}
+
/* Arithmetic with immediate operand */
static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc,
int rt, int rs, int16_t imm)
@@ -2392,6 +2451,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
break;
case OPC_BGEZ:
case OPC_BGEZAL:
+ case OPC_BGEZALS:
case OPC_BGEZALL:
case OPC_BGEZL:
case OPC_BGTZ:
@@ -2400,6 +2460,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
case OPC_BLEZL:
case OPC_BLTZ:
case OPC_BLTZAL:
+ case OPC_BLTZALS:
case OPC_BLTZALL:
case OPC_BLTZL:
/* Compare to zero */
@@ -2412,12 +2473,15 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
case OPC_J:
case OPC_JAL:
case OPC_JALX:
+ case OPC_JALS:
+ case OPC_JALXS:
/* Jump to immediate */
btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset;
break;
case OPC_JR:
case OPC_JALR:
case OPC_JALRC:
+ case OPC_JALRS:
/* Jump to register */
if (offset != 0 && offset != 16) {
/* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
@@ -2446,8 +2510,12 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
ctx->hflags |= MIPS_HFLAG_B;
MIPS_DEBUG("balways");
break;
+ case OPC_BGEZALS:
case OPC_BGEZAL: /* 0 >= 0 */
case OPC_BGEZALL: /* 0 >= 0 likely */
+ ctx->hflags |= (opc == OPC_BGEZALS
+ ? MIPS_HFLAG_BDS16
+ : MIPS_HFLAG_BDS32);
/* Always take and link */
blink = 31;
ctx->hflags |= MIPS_HFLAG_B;
@@ -2459,10 +2527,18 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
/* Treat as NOP. */
MIPS_DEBUG("bnever (NOP)");
goto out;
+ case OPC_BLTZALS:
case OPC_BLTZAL: /* 0 < 0 */
- tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 8);
+ ctx->hflags |= (opc == OPC_BLTZALS
+ ? MIPS_HFLAG_BDS16
+ : MIPS_HFLAG_BDS32);
+ /* Handle as an unconditional branch to get correct delay
+ slot checking. */
+ blink = 31;
+ btgt = ctx->pc + (opc == OPC_BLTZALS ? 6 : 8);
+ ctx->hflags |= MIPS_HFLAG_B;
MIPS_DEBUG("bnever and link");
- goto out;
+ break;
case OPC_BLTZALL: /* 0 < 0 likely */
tcg_gen_movi_tl(cpu_gpr[31], ctx->pc + 8);
/* Skip the instruction in the delay slot */
@@ -2480,29 +2556,33 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
ctx->hflags |= MIPS_HFLAG_B;
MIPS_DEBUG("j " TARGET_FMT_lx, btgt);
break;
+ case OPC_JALXS:
case OPC_JALX:
ctx->hflags |= MIPS_HFLAG_BX;
/* Fallthrough */
+ case OPC_JALS:
case OPC_JAL:
blink = 31;
ctx->hflags |= MIPS_HFLAG_B;
- ctx->hflags |= (ctx->hflags & MIPS_HFLAG_M16
+ ctx->hflags |= ((opc == OPC_JALS || opc == OPC_JALXS)
? MIPS_HFLAG_BDS16
: MIPS_HFLAG_BDS32);
MIPS_DEBUG("jal " TARGET_FMT_lx, btgt);
break;
case OPC_JR:
ctx->hflags |= MIPS_HFLAG_BR;
- if (ctx->hflags & MIPS_HFLAG_M16)
- ctx->hflags |= MIPS_HFLAG_BDS16;
+ if (insn_bytes == 4)
+ ctx->hflags |= MIPS_HFLAG_BDS32;
MIPS_DEBUG("jr %s", regnames[rs]);
break;
+ case OPC_JALRS:
case OPC_JALR:
case OPC_JALRC:
blink = rt;
ctx->hflags |= MIPS_HFLAG_BR;
- if (ctx->hflags & MIPS_HFLAG_M16)
- ctx->hflags |= MIPS_HFLAG_BDS16;
+ ctx->hflags |= (opc == OPC_JALRS
+ ? MIPS_HFLAG_BDS16
+ : MIPS_HFLAG_BDS32);
MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
break;
default:
@@ -2540,7 +2620,11 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btgt);
goto likely;
+ case OPC_BGEZALS:
case OPC_BGEZAL:
+ ctx->hflags |= (opc == OPC_BGEZALS
+ ? MIPS_HFLAG_BDS16
+ : MIPS_HFLAG_BDS32);
tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btgt);
blink = 31;
@@ -2574,7 +2658,11 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0);
MIPS_DEBUG("bltzl %s, " TARGET_FMT_lx, regnames[rs], btgt);
goto likely;
+ case OPC_BLTZALS:
case OPC_BLTZAL:
+ ctx->hflags |= (opc == OPC_BLTZALS
+ ? MIPS_HFLAG_BDS16
+ : MIPS_HFLAG_BDS32);
tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0);
blink = 31;
MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btgt);
@@ -5703,6 +5791,146 @@ static void gen_compute_branch1 (CPUState *env, DisasContext *ctx, uint32_t op,
#define FOP(func, fmt) (((fmt) << 21) | (func))
+enum fopcode {
+ OPC_ADD_S = FOP(0, FMT_S),
+ OPC_SUB_S = FOP(1, FMT_S),
+ OPC_MUL_S = FOP(2, FMT_S),
+ OPC_DIV_S = FOP(3, FMT_S),
+ OPC_SQRT_S = FOP(4, FMT_S),
+ OPC_ABS_S = FOP(5, FMT_S),
+ OPC_MOV_S = FOP(6, FMT_S),
+ OPC_NEG_S = FOP(7, FMT_S),
+ OPC_ROUND_L_S = FOP(8, FMT_S),
+ OPC_TRUNC_L_S = FOP(9, FMT_S),
+ OPC_CEIL_L_S = FOP(10, FMT_S),
+ OPC_FLOOR_L_S = FOP(11, FMT_S),
+ OPC_ROUND_W_S = FOP(12, FMT_S),
+ OPC_TRUNC_W_S = FOP(13, FMT_S),
+ OPC_CEIL_W_S = FOP(14, FMT_S),
+ OPC_FLOOR_W_S = FOP(15, FMT_S),
+ OPC_MOVCF_S = FOP(17, FMT_S),
+ OPC_MOVZ_S = FOP(18, FMT_S),
+ OPC_MOVN_S = FOP(19, FMT_S),
+ OPC_RECIP_S = FOP(21, FMT_S),
+ OPC_RSQRT_S = FOP(22, FMT_S),
+ OPC_RECIP2_S = FOP(28, FMT_S),
+ OPC_RECIP1_S = FOP(29, FMT_S),
+ OPC_RSQRT1_S = FOP(30, FMT_S),
+ OPC_RSQRT2_S = FOP(31, FMT_S),
+ OPC_CVT_D_S = FOP(33, FMT_S),
+ OPC_CVT_W_S = FOP(36, FMT_S),
+ OPC_CVT_L_S = FOP(37, FMT_S),
+ OPC_CVT_PS_S = FOP(38, FMT_S),
+ OPC_CMP_F_S = FOP (48, FMT_S),
+ OPC_CMP_UN_S = FOP (49, FMT_S),
+ OPC_CMP_EQ_S = FOP (50, FMT_S),
+ OPC_CMP_UEQ_S = FOP (51, FMT_S),
+ OPC_CMP_OLT_S = FOP (52, FMT_S),
+ OPC_CMP_ULT_S = FOP (53, FMT_S),
+ OPC_CMP_OLE_S = FOP (54, FMT_S),
+ OPC_CMP_ULE_S = FOP (55, FMT_S),
+ OPC_CMP_SF_S = FOP (56, FMT_S),
+ OPC_CMP_NGLE_S = FOP (57, FMT_S),
+ OPC_CMP_SEQ_S = FOP (58, FMT_S),
+ OPC_CMP_NGL_S = FOP (59, FMT_S),
+ OPC_CMP_LT_S = FOP (60, FMT_S),
+ OPC_CMP_NGE_S = FOP (61, FMT_S),
+ OPC_CMP_LE_S = FOP (62, FMT_S),
+ OPC_CMP_NGT_S = FOP (63, FMT_S),
+
+ OPC_ADD_D = FOP(0, FMT_D),
+ OPC_SUB_D = FOP(1, FMT_D),
+ OPC_MUL_D = FOP(2, FMT_D),
+ OPC_DIV_D = FOP(3, FMT_D),
+ OPC_SQRT_D = FOP(4, FMT_D),
+ OPC_ABS_D = FOP(5, FMT_D),
+ OPC_MOV_D = FOP(6, FMT_D),
+ OPC_NEG_D = FOP(7, FMT_D),
+ OPC_ROUND_L_D = FOP(8, FMT_D),
+ OPC_TRUNC_L_D = FOP(9, FMT_D),
+ OPC_CEIL_L_D = FOP(10, FMT_D),
+ OPC_FLOOR_L_D = FOP(11, FMT_D),
+ OPC_ROUND_W_D = FOP(12, FMT_D),
+ OPC_TRUNC_W_D = FOP(13, FMT_D),
+ OPC_CEIL_W_D = FOP(14, FMT_D),
+ OPC_FLOOR_W_D = FOP(15, FMT_D),
+ OPC_MOVCF_D = FOP(17, FMT_D),
+ OPC_MOVZ_D = FOP(18, FMT_D),
+ OPC_MOVN_D = FOP(19, FMT_D),
+ OPC_RECIP_D = FOP(21, FMT_D),
+ OPC_RSQRT_D = FOP(22, FMT_D),
+ OPC_RECIP2_D = FOP(28, FMT_D),
+ OPC_RECIP1_D = FOP(29, FMT_D),
+ OPC_RSQRT1_D = FOP(30, FMT_D),
+ OPC_RSQRT2_D = FOP(31, FMT_D),
+ OPC_CVT_S_D = FOP(32, FMT_D),
+ OPC_CVT_W_D = FOP(36, FMT_D),
+ OPC_CVT_L_D = FOP(37, FMT_D),
+ OPC_CMP_F_D = FOP (48, FMT_D),
+ OPC_CMP_UN_D = FOP (49, FMT_D),
+ OPC_CMP_EQ_D = FOP (50, FMT_D),
+ OPC_CMP_UEQ_D = FOP (51, FMT_D),
+ OPC_CMP_OLT_D = FOP (52, FMT_D),
+ OPC_CMP_ULT_D = FOP (53, FMT_D),
+ OPC_CMP_OLE_D = FOP (54, FMT_D),
+ OPC_CMP_ULE_D = FOP (55, FMT_D),
+ OPC_CMP_SF_D = FOP (56, FMT_D),
+ OPC_CMP_NGLE_D = FOP (57, FMT_D),
+ OPC_CMP_SEQ_D = FOP (58, FMT_D),
+ OPC_CMP_NGL_D = FOP (59, FMT_D),
+ OPC_CMP_LT_D = FOP (60, FMT_D),
+ OPC_CMP_NGE_D = FOP (61, FMT_D),
+ OPC_CMP_LE_D = FOP (62, FMT_D),
+ OPC_CMP_NGT_D = FOP (63, FMT_D),
+
+ OPC_CVT_S_W = FOP(32, FMT_W),
+ OPC_CVT_D_W = FOP(33, FMT_W),
+ OPC_CVT_S_L = FOP(32, FMT_L),
+ OPC_CVT_D_L = FOP(33, FMT_L),
+ OPC_CVT_PS_PW = FOP(38, FMT_W),
+
+ OPC_ADD_PS = FOP(0, FMT_PS),
+ OPC_SUB_PS = FOP(1, FMT_PS),
+ OPC_MUL_PS = FOP(2, FMT_PS),
+ OPC_DIV_PS = FOP(3, FMT_PS),
+ OPC_ABS_PS = FOP(5, FMT_PS),
+ OPC_MOV_PS = FOP(6, FMT_PS),
+ OPC_NEG_PS = FOP(7, FMT_PS),
+ OPC_MOVCF_PS = FOP(17, FMT_PS),
+ OPC_MOVZ_PS = FOP(18, FMT_PS),
+ OPC_MOVN_PS = FOP(19, FMT_PS),
+ OPC_ADDR_PS = FOP(24, FMT_PS),
+ OPC_MULR_PS = FOP(26, FMT_PS),
+ OPC_RECIP2_PS = FOP(28, FMT_PS),
+ OPC_RECIP1_PS = FOP(29, FMT_PS),
+ OPC_RSQRT1_PS = FOP(30, FMT_PS),
+ OPC_RSQRT2_PS = FOP(31, FMT_PS),
+
+ OPC_CVT_S_PU = FOP(32, FMT_PS),
+ OPC_CVT_PW_PS = FOP(36, FMT_PS),
+ OPC_CVT_S_PL = FOP(40, FMT_PS),
+ OPC_PLL_PS = FOP(44, FMT_PS),
+ OPC_PLU_PS = FOP(45, FMT_PS),
+ OPC_PUL_PS = FOP(46, FMT_PS),
+ OPC_PUU_PS = FOP(47, FMT_PS),
+ OPC_CMP_F_PS = FOP (48, FMT_PS),
+ OPC_CMP_UN_PS = FOP (49, FMT_PS),
+ OPC_CMP_EQ_PS = FOP (50, FMT_PS),
+ OPC_CMP_UEQ_PS = FOP (51, FMT_PS),
+ OPC_CMP_OLT_PS = FOP (52, FMT_PS),
+ OPC_CMP_ULT_PS = FOP (53, FMT_PS),
+ OPC_CMP_OLE_PS = FOP (54, FMT_PS),
+ OPC_CMP_ULE_PS = FOP (55, FMT_PS),
+ OPC_CMP_SF_PS = FOP (56, FMT_PS),
+ OPC_CMP_NGLE_PS = FOP (57, FMT_PS),
+ OPC_CMP_SEQ_PS = FOP (58, FMT_PS),
+ OPC_CMP_NGL_PS = FOP (59, FMT_PS),
+ OPC_CMP_LT_PS = FOP (60, FMT_PS),
+ OPC_CMP_NGE_PS = FOP (61, FMT_PS),
+ OPC_CMP_LE_PS = FOP (62, FMT_PS),
+ OPC_CMP_NGT_PS = FOP (63, FMT_PS),
+};
+
static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
{
const char *opn = "cp1 move";
@@ -5883,7 +6111,7 @@ static inline void gen_movcf_ps (int fs, int fd, int cc, int tf)
}
-static void gen_farith (DisasContext *ctx, uint32_t op1,
+static void gen_farith (DisasContext *ctx, enum fopcode op1,
int ft, int fs, int fd, int cc)
{
const char *opn = "farith";
@@ -5926,8 +6154,8 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
enum { BINOP, CMPOP, OTHEROP } optype = OTHEROP;
uint32_t func = ctx->opcode & 0x3f;
- switch (ctx->opcode & FOP(0x3f, 0x1f)) {
- case FOP(0, 16):
+ switch (op1) {
+ case OPC_ADD_S:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
TCGv_i32 fp1 = tcg_temp_new_i32();
@@ -5942,7 +6170,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
opn = "add.s";
optype = BINOP;
break;
- case FOP(1, 16):
+ case OPC_SUB_S:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
TCGv_i32 fp1 = tcg_temp_new_i32();
@@ -5957,7 +6185,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
opn = "sub.s";
optype = BINOP;
break;
- case FOP(2, 16):
+ case OPC_MUL_S:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
TCGv_i32 fp1 = tcg_temp_new_i32();
@@ -5972,7 +6200,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
opn = "mul.s";
optype = BINOP;
break;
- case FOP(3, 16):
+ case OPC_DIV_S:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
TCGv_i32 fp1 = tcg_temp_new_i32();
@@ -5987,7 +6215,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
opn = "div.s";
optype = BINOP;
break;
- case FOP(4, 16):
+ case OPC_SQRT_S:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -5998,7 +6226,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "sqrt.s";
break;
- case FOP(5, 16):
+ case OPC_ABS_S:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6009,7 +6237,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "abs.s";
break;
- case FOP(6, 16):
+ case OPC_MOV_S:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6019,7 +6247,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "mov.s";
break;
- case FOP(7, 16):
+ case OPC_NEG_S:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6030,7 +6258,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "neg.s";
break;
- case FOP(8, 16):
+ case OPC_ROUND_L_S:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6044,7 +6272,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "round.l.s";
break;
- case FOP(9, 16):
+ case OPC_TRUNC_L_S:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6058,7 +6286,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "trunc.l.s";
break;
- case FOP(10, 16):
+ case OPC_CEIL_L_S:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6072,7 +6300,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "ceil.l.s";
break;
- case FOP(11, 16):
+ case OPC_FLOOR_L_S:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6086,7 +6314,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "floor.l.s";
break;
- case FOP(12, 16):
+ case OPC_ROUND_W_S:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6097,7 +6325,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "round.w.s";
break;
- case FOP(13, 16):
+ case OPC_TRUNC_W_S:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6108,7 +6336,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "trunc.w.s";
break;
- case FOP(14, 16):
+ case OPC_CEIL_W_S:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6119,7 +6347,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "ceil.w.s";
break;
- case FOP(15, 16):
+ case OPC_FLOOR_W_S:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6130,11 +6358,11 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "floor.w.s";
break;
- case FOP(17, 16):
+ case OPC_MOVCF_S:
gen_movcf_s(fs, fd, (ft >> 2) & 0x7, ft & 0x1);
opn = "movcf.s";
break;
- case FOP(18, 16):
+ case OPC_MOVZ_S:
{
int l1 = gen_new_label();
TCGv_i32 fp0;
@@ -6150,7 +6378,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "movz.s";
break;
- case FOP(19, 16):
+ case OPC_MOVN_S:
{
int l1 = gen_new_label();
TCGv_i32 fp0;
@@ -6166,7 +6394,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "movn.s";
break;
- case FOP(21, 16):
+ case OPC_RECIP_S:
check_cop1x(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6178,7 +6406,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "recip.s";
break;
- case FOP(22, 16):
+ case OPC_RSQRT_S:
check_cop1x(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6190,7 +6418,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "rsqrt.s";
break;
- case FOP(28, 16):
+ case OPC_RECIP2_S:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6205,7 +6433,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "recip2.s";
break;
- case FOP(29, 16):
+ case OPC_RECIP1_S:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6217,7 +6445,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "recip1.s";
break;
- case FOP(30, 16):
+ case OPC_RSQRT1_S:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6229,7 +6457,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "rsqrt1.s";
break;
- case FOP(31, 16):
+ case OPC_RSQRT2_S:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6244,7 +6472,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "rsqrt2.s";
break;
- case FOP(33, 16):
+ case OPC_CVT_D_S:
check_cp1_registers(ctx, fd);
{
TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6258,7 +6486,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.d.s";
break;
- case FOP(36, 16):
+ case OPC_CVT_W_S:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6269,7 +6497,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.w.s";
break;
- case FOP(37, 16):
+ case OPC_CVT_L_S:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6283,7 +6511,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.l.s";
break;
- case FOP(38, 16):
+ case OPC_CVT_PS_S:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp64 = tcg_temp_new_i64();
@@ -6300,41 +6528,31 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.ps.s";
break;
- case FOP(48, 16):
- case FOP(49, 16):
- case FOP(50, 16):
- case FOP(51, 16):
- case FOP(52, 16):
- case FOP(53, 16):
- case FOP(54, 16):
- case FOP(55, 16):
- case FOP(56, 16):
- case FOP(57, 16):
- case FOP(58, 16):
- case FOP(59, 16):
- case FOP(60, 16):
- case FOP(61, 16):
- case FOP(62, 16):
- case FOP(63, 16):
- {
- TCGv_i32 fp0 = tcg_temp_new_i32();
- TCGv_i32 fp1 = tcg_temp_new_i32();
-
- gen_load_fpr32(fp0, fs);
- gen_load_fpr32(fp1, ft);
- if (ctx->opcode & (1 << 6)) {
- check_cop1x(ctx);
- gen_cmpabs_s(func-48, fp0, fp1, cc);
- opn = condnames_abs[func-48];
- } else {
- gen_cmp_s(func-48, fp0, fp1, cc);
- opn = condnames[func-48];
- }
- tcg_temp_free_i32(fp0);
- tcg_temp_free_i32(fp1);
+ case OPC_CMP_F_S:
+ case OPC_CMP_UN_S:
+ case OPC_CMP_EQ_S:
+ case OPC_CMP_UEQ_S:
+ case OPC_CMP_OLT_S:
+ case OPC_CMP_ULT_S:
+ case OPC_CMP_OLE_S:
+ case OPC_CMP_ULE_S:
+ case OPC_CMP_SF_S:
+ case OPC_CMP_NGLE_S:
+ case OPC_CMP_SEQ_S:
+ case OPC_CMP_NGL_S:
+ case OPC_CMP_LT_S:
+ case OPC_CMP_NGE_S:
+ case OPC_CMP_LE_S:
+ case OPC_CMP_NGT_S:
+ if (ctx->opcode & (1 << 6)) {
+ gen_cmpabs_s(ctx, func-48, ft, fs, cc);
+ opn = condnames_abs[func-48];
+ } else {
+ gen_cmp_s(ctx, func-48, ft, fs, cc);
+ opn = condnames[func-48];
}
break;
- case FOP(0, 17):
+ case OPC_ADD_D:
check_cp1_registers(ctx, fs | ft | fd);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6350,7 +6568,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
opn = "add.d";
optype = BINOP;
break;
- case FOP(1, 17):
+ case OPC_SUB_D:
check_cp1_registers(ctx, fs | ft | fd);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6366,7 +6584,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
opn = "sub.d";
optype = BINOP;
break;
- case FOP(2, 17):
+ case OPC_MUL_D:
check_cp1_registers(ctx, fs | ft | fd);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6382,7 +6600,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
opn = "mul.d";
optype = BINOP;
break;
- case FOP(3, 17):
+ case OPC_DIV_D:
check_cp1_registers(ctx, fs | ft | fd);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6398,7 +6616,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
opn = "div.d";
optype = BINOP;
break;
- case FOP(4, 17):
+ case OPC_SQRT_D:
check_cp1_registers(ctx, fs | fd);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6410,7 +6628,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "sqrt.d";
break;
- case FOP(5, 17):
+ case OPC_ABS_D:
check_cp1_registers(ctx, fs | fd);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6422,7 +6640,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "abs.d";
break;
- case FOP(6, 17):
+ case OPC_MOV_D:
check_cp1_registers(ctx, fs | fd);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6433,7 +6651,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "mov.d";
break;
- case FOP(7, 17):
+ case OPC_NEG_D:
check_cp1_registers(ctx, fs | fd);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6445,7 +6663,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "neg.d";
break;
- case FOP(8, 17):
+ case OPC_ROUND_L_D:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6457,7 +6675,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "round.l.d";
break;
- case FOP(9, 17):
+ case OPC_TRUNC_L_D:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6469,7 +6687,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "trunc.l.d";
break;
- case FOP(10, 17):
+ case OPC_CEIL_L_D:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6481,7 +6699,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "ceil.l.d";
break;
- case FOP(11, 17):
+ case OPC_FLOOR_L_D:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6493,7 +6711,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "floor.l.d";
break;
- case FOP(12, 17):
+ case OPC_ROUND_W_D:
check_cp1_registers(ctx, fs);
{
TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6507,7 +6725,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "round.w.d";
break;
- case FOP(13, 17):
+ case OPC_TRUNC_W_D:
check_cp1_registers(ctx, fs);
{
TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6521,7 +6739,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "trunc.w.d";
break;
- case FOP(14, 17):
+ case OPC_CEIL_W_D:
check_cp1_registers(ctx, fs);
{
TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6535,7 +6753,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "ceil.w.d";
break;
- case FOP(15, 17):
+ case OPC_FLOOR_W_D:
check_cp1_registers(ctx, fs);
{
TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6549,11 +6767,11 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "floor.w.d";
break;
- case FOP(17, 17):
+ case OPC_MOVCF_D:
gen_movcf_d(ctx, fs, fd, (ft >> 2) & 0x7, ft & 0x1);
opn = "movcf.d";
break;
- case FOP(18, 17):
+ case OPC_MOVZ_D:
{
int l1 = gen_new_label();
TCGv_i64 fp0;
@@ -6569,7 +6787,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "movz.d";
break;
- case FOP(19, 17):
+ case OPC_MOVN_D:
{
int l1 = gen_new_label();
TCGv_i64 fp0;
@@ -6585,7 +6803,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "movn.d";
break;
- case FOP(21, 17):
+ case OPC_RECIP_D:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6597,7 +6815,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "recip.d";
break;
- case FOP(22, 17):
+ case OPC_RSQRT_D:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6609,7 +6827,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "rsqrt.d";
break;
- case FOP(28, 17):
+ case OPC_RECIP2_D:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6624,7 +6842,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "recip2.d";
break;
- case FOP(29, 17):
+ case OPC_RECIP1_D:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6636,7 +6854,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "recip1.d";
break;
- case FOP(30, 17):
+ case OPC_RSQRT1_D:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6648,7 +6866,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "rsqrt1.d";
break;
- case FOP(31, 17):
+ case OPC_RSQRT2_D:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6663,43 +6881,31 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "rsqrt2.d";
break;
- case FOP(48, 17):
- case FOP(49, 17):
- case FOP(50, 17):
- case FOP(51, 17):
- case FOP(52, 17):
- case FOP(53, 17):
- case FOP(54, 17):
- case FOP(55, 17):
- case FOP(56, 17):
- case FOP(57, 17):
- case FOP(58, 17):
- case FOP(59, 17):
- case FOP(60, 17):
- case FOP(61, 17):
- case FOP(62, 17):
- case FOP(63, 17):
- {
- TCGv_i64 fp0 = tcg_temp_new_i64();
- TCGv_i64 fp1 = tcg_temp_new_i64();
-
- gen_load_fpr64(ctx, fp0, fs);
- gen_load_fpr64(ctx, fp1, ft);
- if (ctx->opcode & (1 << 6)) {
- check_cop1x(ctx);
- check_cp1_registers(ctx, fs | ft);
- gen_cmpabs_d(func-48, fp0, fp1, cc);
- opn = condnames_abs[func-48];
- } else {
- check_cp1_registers(ctx, fs | ft);
- gen_cmp_d(func-48, fp0, fp1, cc);
- opn = condnames[func-48];
- }
- tcg_temp_free_i64(fp0);
- tcg_temp_free_i64(fp1);
+ case OPC_CMP_F_D:
+ case OPC_CMP_UN_D:
+ case OPC_CMP_EQ_D:
+ case OPC_CMP_UEQ_D:
+ case OPC_CMP_OLT_D:
+ case OPC_CMP_ULT_D:
+ case OPC_CMP_OLE_D:
+ case OPC_CMP_ULE_D:
+ case OPC_CMP_SF_D:
+ case OPC_CMP_NGLE_D:
+ case OPC_CMP_SEQ_D:
+ case OPC_CMP_NGL_D:
+ case OPC_CMP_LT_D:
+ case OPC_CMP_NGE_D:
+ case OPC_CMP_LE_D:
+ case OPC_CMP_NGT_D:
+ if (ctx->opcode & (1 << 6)) {
+ gen_cmpabs_d(ctx, func-48, ft, fs, cc);
+ opn = condnames_abs[func-48];
+ } else {
+ gen_cmp_d(ctx, func-48, ft, fs, cc);
+ opn = condnames[func-48];
}
break;
- case FOP(32, 17):
+ case OPC_CVT_S_D:
check_cp1_registers(ctx, fs);
{
TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6713,7 +6919,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.s.d";
break;
- case FOP(36, 17):
+ case OPC_CVT_W_D:
check_cp1_registers(ctx, fs);
{
TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6727,7 +6933,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.w.d";
break;
- case FOP(37, 17):
+ case OPC_CVT_L_D:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6739,7 +6945,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.l.d";
break;
- case FOP(32, 20):
+ case OPC_CVT_S_W:
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -6750,7 +6956,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.s.w";
break;
- case FOP(33, 20):
+ case OPC_CVT_D_W:
check_cp1_registers(ctx, fd);
{
TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6764,7 +6970,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.d.w";
break;
- case FOP(32, 21):
+ case OPC_CVT_S_L:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp32 = tcg_temp_new_i32();
@@ -6778,7 +6984,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.s.l";
break;
- case FOP(33, 21):
+ case OPC_CVT_D_L:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6790,7 +6996,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.d.l";
break;
- case FOP(38, 20):
+ case OPC_CVT_PS_PW:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6802,7 +7008,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.ps.pw";
break;
- case FOP(0, 22):
+ case OPC_ADD_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6817,7 +7023,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "add.ps";
break;
- case FOP(1, 22):
+ case OPC_SUB_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6832,7 +7038,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "sub.ps";
break;
- case FOP(2, 22):
+ case OPC_MUL_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6847,7 +7053,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "mul.ps";
break;
- case FOP(5, 22):
+ case OPC_ABS_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6859,7 +7065,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "abs.ps";
break;
- case FOP(6, 22):
+ case OPC_MOV_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6870,7 +7076,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "mov.ps";
break;
- case FOP(7, 22):
+ case OPC_NEG_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6882,12 +7088,12 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "neg.ps";
break;
- case FOP(17, 22):
+ case OPC_MOVCF_PS:
check_cp1_64bitmode(ctx);
gen_movcf_ps(fs, fd, (ft >> 2) & 0x7, ft & 0x1);
opn = "movcf.ps";
break;
- case FOP(18, 22):
+ case OPC_MOVZ_PS:
check_cp1_64bitmode(ctx);
{
int l1 = gen_new_label();
@@ -6903,7 +7109,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "movz.ps";
break;
- case FOP(19, 22):
+ case OPC_MOVN_PS:
check_cp1_64bitmode(ctx);
{
int l1 = gen_new_label();
@@ -6920,7 +7126,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "movn.ps";
break;
- case FOP(24, 22):
+ case OPC_ADDR_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6935,7 +7141,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "addr.ps";
break;
- case FOP(26, 22):
+ case OPC_MULR_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6950,7 +7156,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "mulr.ps";
break;
- case FOP(28, 22):
+ case OPC_RECIP2_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6965,7 +7171,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "recip2.ps";
break;
- case FOP(29, 22):
+ case OPC_RECIP1_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6977,7 +7183,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "recip1.ps";
break;
- case FOP(30, 22):
+ case OPC_RSQRT1_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -6989,7 +7195,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "rsqrt1.ps";
break;
- case FOP(31, 22):
+ case OPC_RSQRT2_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -7004,7 +7210,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "rsqrt2.ps";
break;
- case FOP(32, 22):
+ case OPC_CVT_S_PU:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -7016,7 +7222,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.s.pu";
break;
- case FOP(36, 22):
+ case OPC_CVT_PW_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i64 fp0 = tcg_temp_new_i64();
@@ -7028,7 +7234,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.pw.ps";
break;
- case FOP(40, 22):
+ case OPC_CVT_S_PL:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -7040,7 +7246,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "cvt.s.pl";
break;
- case FOP(44, 22):
+ case OPC_PLL_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -7055,7 +7261,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "pll.ps";
break;
- case FOP(45, 22):
+ case OPC_PLU_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -7070,7 +7276,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "plu.ps";
break;
- case FOP(46, 22):
+ case OPC_PUL_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -7085,7 +7291,7 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "pul.ps";
break;
- case FOP(47, 22):
+ case OPC_PUU_PS:
check_cp1_64bitmode(ctx);
{
TCGv_i32 fp0 = tcg_temp_new_i32();
@@ -7100,38 +7306,28 @@ static void gen_farith (DisasContext *ctx, uint32_t op1,
}
opn = "puu.ps";
break;
- case FOP(48, 22):
- case FOP(49, 22):
- case FOP(50, 22):
- case FOP(51, 22):
- case FOP(52, 22):
- case FOP(53, 22):
- case FOP(54, 22):
- case FOP(55, 22):
- case FOP(56, 22):
- case FOP(57, 22):
- case FOP(58, 22):
- case FOP(59, 22):
- case FOP(60, 22):
- case FOP(61, 22):
- case FOP(62, 22):
- case FOP(63, 22):
- check_cp1_64bitmode(ctx);
- {
- TCGv_i64 fp0 = tcg_temp_new_i64();
- TCGv_i64 fp1 = tcg_temp_new_i64();
-
- gen_load_fpr64(ctx, fp0, fs);
- gen_load_fpr64(ctx, fp1, ft);
- if (ctx->opcode & (1 << 6)) {
- gen_cmpabs_ps(func-48, fp0, fp1, cc);
- opn = condnames_abs[func-48];
- } else {
- gen_cmp_ps(func-48, fp0, fp1, cc);
- opn = condnames[func-48];
- }
- tcg_temp_free_i64(fp0);
- tcg_temp_free_i64(fp1);
+ case OPC_CMP_F_PS:
+ case OPC_CMP_UN_PS:
+ case OPC_CMP_EQ_PS:
+ case OPC_CMP_UEQ_PS:
+ case OPC_CMP_OLT_PS:
+ case OPC_CMP_ULT_PS:
+ case OPC_CMP_OLE_PS:
+ case OPC_CMP_ULE_PS:
+ case OPC_CMP_SF_PS:
+ case OPC_CMP_NGLE_PS:
+ case OPC_CMP_SEQ_PS:
+ case OPC_CMP_NGL_PS:
+ case OPC_CMP_LT_PS:
+ case OPC_CMP_NGE_PS:
+ case OPC_CMP_LE_PS:
+ case OPC_CMP_NGT_PS:
+ if (ctx->opcode & (1 << 6)) {
+ gen_cmpabs_ps(ctx, func-48, ft, fs, cc);
+ opn = condnames_abs[func-48];
+ } else {
+ gen_cmp_ps(ctx, func-48, ft, fs, cc);
+ opn = condnames[func-48];
}
break;
default:
@@ -7528,6 +7724,52 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
fregnames[fs], fregnames[ft]);
}
+static void
+gen_rdhwr (CPUState *env, DisasContext *ctx, int rt, int rd)
+{
+ TCGv t0;
+
+ check_insn(env, ctx, ISA_MIPS32R2);
+ t0 = tcg_temp_new();
+
+ switch (rd) {
+ case 0:
+ save_cpu_state(ctx, 1);
+ gen_helper_rdhwr_cpunum(t0);
+ gen_store_gpr(t0, rt);
+ break;
+ case 1:
+ save_cpu_state(ctx, 1);
+ gen_helper_rdhwr_synci_step(t0);
+ gen_store_gpr(t0, rt);
+ break;
+ case 2:
+ save_cpu_state(ctx, 1);
+ gen_helper_rdhwr_cc(t0);
+ gen_store_gpr(t0, rt);
+ break;
+ case 3:
+ save_cpu_state(ctx, 1);
+ gen_helper_rdhwr_ccres(t0);
+ gen_store_gpr(t0, rt);
+ break;
+ case 29:
+#if defined(CONFIG_USER_ONLY)
+ tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, tls_value));
+ gen_store_gpr(t0, rt);
+ break;
+#else
+ /* XXX: Some CPUs implement this in hardware.
+ Not supported yet. */
+#endif
+ default: /* Invalid */
+ MIPS_INVAL("rdhwr");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ tcg_temp_free(t0);
+}
+
static void handle_delay_slot (CPUState *env, DisasContext *ctx,
int insn_bytes)
{
@@ -7567,7 +7809,7 @@ static void handle_delay_slot (CPUState *env, DisasContext *ctx,
case MIPS_HFLAG_BR:
/* unconditional branch to register */
MIPS_DEBUG("branch to register");
- if (env->insn_flags & ASE_MIPS16) {
+ if (env->insn_flags & (ASE_MIPS16 | ASE_MICROMIPS)) {
TCGv t0 = tcg_temp_new();
TCGv_i32 t1 = tcg_temp_new_i32();
@@ -8279,7 +8521,7 @@ static int decode_mips16_opc (CPUState *env, DisasContext *ctx,
offset = (((ctx->opcode & 0x1f) << 21)
| ((ctx->opcode >> 5) & 0x1f) << 16
| offset) << 2;
- op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALX : OPC_JAL;
+ op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALXS : OPC_JALS;
gen_compute_branch(ctx, op, 4, rx, ry, offset);
n_bytes = 4;
*is_branch = 1;
@@ -8518,7 +8760,7 @@ static int decode_mips16_opc (CPUState *env, DisasContext *ctx,
int ra = (ctx->opcode >> 5) & 0x1;
if (link) {
- op = nd ? OPC_JALRC : OPC_JALR;
+ op = nd ? OPC_JALRC : OPC_JALRS;
} else {
op = OPC_JR;
}
@@ -8688,6 +8930,2358 @@ static int decode_mips16_opc (CPUState *env, DisasContext *ctx,
return n_bytes;
}
+/* microMIPS extension to MIPS32 */
+
+/* microMIPS32 major opcodes */
+
+enum {
+ POOL32A = 0x00,
+ POOL16A = 0x01,
+ LBU16 = 0x02,
+ MOVE16 = 0x03,
+ ADDI32 = 0x04,
+ LBU32 = 0x05,
+ SB32 = 0x06,
+ LB32 = 0x07,
+
+ POOL32B = 0x08,
+ POOL16B = 0x09,
+ LHU16 = 0x0a,
+ ANDI16 = 0x0b,
+ ADDIU32 = 0x0c,
+ LHU32 = 0x0d,
+ SH32 = 0x0e,
+ LH32 = 0x0f,
+
+ POOL32I = 0x10,
+ POOL16C = 0x11,
+ LWSP16 = 0x12,
+ POOL16D = 0x13,
+ ORI32 = 0x14,
+ POOL32F = 0x15,
+ POOL32S = 0x16,
+ DADDIU32 = 0x17,
+
+ POOL32C = 0x18,
+ LWGP16 = 0x19,
+ LW16 = 0x1a,
+ POOL16E = 0x1b,
+ XORI32 = 0x1c,
+ JALS32 = 0x1d,
+ ADDIUPC = 0x1e,
+ POOL48A = 0x1f,
+
+ /* 0x20 is reserved */
+ RES_20 = 0x20,
+ POOL16F = 0x21,
+ SB16 = 0x22,
+ BEQZ16 = 0x23,
+ SLTI32 = 0x24,
+ BEQ32 = 0x25,
+ SWC132 = 0x26,
+ LWC132 = 0x27,
+
+ /* 0x28 and 0x29 are reserved */
+ RES_28 = 0x28,
+ RES_29 = 0x29,
+ SH16 = 0x2a,
+ BNEZ16 = 0x2b,
+ SLTIU32 = 0x2c,
+ BNE32 = 0x2d,
+ SDC132 = 0x2e,
+ LDC132 = 0x2f,
+
+ /* 0x30 and 0x31 are reserved */
+ RES_30 = 0x30,
+ RES_31 = 0x31,
+ SWSP16 = 0x32,
+ B16 = 0x33,
+ ANDI32 = 0x34,
+ J32 = 0x35,
+ SD32 = 0x36,
+ LD32 = 0x37,
+
+ /* 0x38 and 0x39 are reserved */
+ RES_38 = 0x38,
+ RES_39 = 0x39,
+ SW16 = 0x3a,
+ LI16 = 0x3b,
+ JALX32 = 0x3c,
+ JAL32 = 0x3d,
+ SW32 = 0x3e,
+ LW32 = 0x3f
+};
+
+/* POOL32A encoding of minor opcode field */
+
+enum {
+ /* These opcodes are distinguished only by bits 9..6; those bits are
+ * what are recorded below. */
+ SLL32 = 0x0,
+ SRL32 = 0x1,
+ SRA = 0x2,
+ ROTR = 0x3,
+
+ SLLV = 0x0,
+ SRLV = 0x1,
+ SRAV = 0x2,
+ ROTRV = 0x3,
+ ADD = 0x4,
+ ADDU32 = 0x5,
+ SUB = 0x6,
+ SUBU32 = 0x7,
+ MUL = 0x8,
+ AND = 0x9,
+ OR32 = 0xa,
+ NOR = 0xb,
+ XOR32 = 0xc,
+ SLT = 0xd,
+ SLTU = 0xe,
+
+ MOVN = 0x0,
+ MOVZ = 0x1,
+ LWXS = 0x4,
+
+ /* The following can be distinguished by their lower 6 bits. */
+ INS = 0x0c,
+ EXT = 0x2c,
+ POOL32AXF = 0x3c
+};
+
+/* POOL32AXF encoding of minor opcode field extension */
+
+enum {
+ /* bits 11..6 */
+ TEQ = 0x00,
+ TGE = 0x08,
+ TGEU = 0x10,
+ TLT = 0x20,
+ TLTU = 0x28,
+ TNE = 0x30,
+
+ MFC0 = 0x03,
+ MTC0 = 0x0b,
+
+ /* bits 13..12 for 0x01 */
+ MFHI_ACC = 0x0,
+ MFLO_ACC = 0x1,
+ MTHI_ACC = 0x2,
+ MTLO_ACC = 0x3,
+
+ /* bits 13..12 for 0x2a */
+ MADD_ACC = 0x0,
+ MADDU_ACC = 0x1,
+ MSUB_ACC = 0x2,
+ MSUBU_ACC = 0x3,
+
+ /* bits 13..12 for 0x32 */
+ MULT_ACC = 0x0,
+ MULTU_ACC = 0x0,
+
+ /* bits 15..12 for 0x2c */
+ SEB = 0x2,
+ SEH = 0x3,
+ CLO = 0x4,
+ CLZ = 0x5,
+ RDHWR = 0x6,
+ WSBH = 0x7,
+ MULT = 0x8,
+ MULTU = 0x9,
+ DIV = 0xa,
+ DIVU = 0xb,
+ MADD = 0xc,
+ MADDU = 0xd,
+ MSUB = 0xe,
+ MSUBU = 0xf,
+
+ /* bits 15..12 for 0x34 */
+ MFC2 = 0x4,
+ MTC2 = 0x5,
+ MFHC2 = 0x8,
+ MTHC2 = 0x9,
+ CFC2 = 0xc,
+ CTC2 = 0xd,
+
+ /* bits 15..12 for 0x3c */
+ JALR = 0x0,
+ JR = 0x0, /* alias */
+ JALR_HB = 0x1,
+ JALRS = 0x4,
+ JALRS_HB = 0x5,
+
+ /* bits 15..12 for 0x05 */
+ RDPGPR = 0xe,
+ WRPGPR = 0xf,
+
+ /* bits 15..12 for 0x0d */
+ TLBP = 0x0,
+ TLBR = 0x1,
+ TLBWI = 0x2,
+ TLBWR = 0x3,
+ WAIT = 0x9,
+ IRET = 0xd,
+ DERET = 0xe,
+ ERET = 0xf,
+
+ /* bits 15..12 for 0x15 */
+ DMT = 0x0,
+ DVPE = 0x1,
+ EMT = 0x2,
+ EVPE = 0x3,
+
+ /* bits 15..12 for 0x1d */
+ DI = 0x4,
+ EI = 0x5,
+
+ /* bits 15..12 for 0x2d */
+ SYNC = 0x6,
+ SYSCALL = 0x8,
+ SDBBP = 0xd,
+
+ /* bits 15..12 for 0x35 */
+ MFHI32 = 0x0,
+ MFLO32 = 0x1,
+ MTHI32 = 0x2,
+ MTLO32 = 0x3,
+};
+
+/* POOL32B encoding of minor opcode field (bits 15..12) */
+
+enum {
+ LWC2 = 0x0,
+ LWP = 0x1,
+ LDP = 0x4,
+ LWM32 = 0x5,
+ CACHE = 0x6,
+ LDM = 0x7,
+ SWC2 = 0x8,
+ SWP = 0x9,
+ SDP = 0xc,
+ SWM32 = 0xd,
+ SDM = 0xf
+};
+
+/* POOL32C encoding of minor opcode field (bits 15..12) */
+
+enum {
+ LWL = 0x0,
+ SWL = 0x8,
+ LWR = 0x1,
+ SWR = 0x9,
+ PREF = 0x2,
+ /* 0xa is reserved */
+ LL = 0x3,
+ SC = 0xb,
+ LDL = 0x4,
+ SDL = 0xc,
+ LDR = 0x5,
+ SDR = 0xd,
+ /* 0x6 is reserved */
+ LWU = 0xe,
+ LLD = 0x7,
+ SCD = 0xf
+};
+
+/* POOL32F encoding of minor opcode field (bits 5..0) */
+
+enum {
+ /* These are the bit 7..6 values */
+ ADD_FMT = 0x0,
+ MOVN_FMT = 0x0,
+
+ SUB_FMT = 0x1,
+ MOVZ_FMT = 0x1,
+
+ MUL_FMT = 0x2,
+
+ DIV_FMT = 0x3,
+
+ /* These are the bit 8..6 values */
+ RSQRT2_FMT = 0x0,
+ MOVF_FMT = 0x0,
+
+ LWXC1 = 0x1,
+ MOVT_FMT = 0x1,
+
+ PLL_PS = 0x2,
+ SWXC1 = 0x2,
+
+ PLU_PS = 0x3,
+ LDXC1 = 0x3,
+
+ PUL_PS = 0x4,
+ SDXC1 = 0x4,
+ RECIP2_FMT = 0x4,
+
+ PUU_PS = 0x5,
+ LUXC1 = 0x5,
+
+ CVT_PS_S = 0x6,
+ SUXC1 = 0x6,
+ ADDR_PS = 0x6,
+ PREFX = 0x6,
+
+ MULR_PS = 0x7,
+
+ MADD_S = 0x01,
+ MADD_D = 0x09,
+ MADD_PS = 0x11,
+ ALNV_PS = 0x19,
+ MSUB_S = 0x21,
+ MSUB_D = 0x29,
+ MSUB_PS = 0x31,
+
+ NMADD_S = 0x02,
+ NMADD_D = 0x0a,
+ NMADD_PS = 0x12,
+ NMSUB_S = 0x22,
+ NMSUB_D = 0x2a,
+ NMSUB_PS = 0x32,
+
+ POOL32FXF = 0x3b,
+
+ CABS_COND_FMT = 0x1c, /* MIPS3D */
+ C_COND_FMT = 0x3c
+};
+
+/* POOL32Fxf encoding of minor opcode extension field */
+
+enum {
+ CVT_L = 0x04,
+ RSQRT_FMT = 0x08,
+ FLOOR_L = 0x0c,
+ CVT_PW_PS = 0x1c,
+ CVT_W = 0x24,
+ SQRT_FMT = 0x28,
+ FLOOR_W = 0x2c,
+ CVT_PS_PW = 0x3c,
+ CFC1 = 0x40,
+ RECIP_FMT = 0x48,
+ CEIL_L = 0x4c,
+ CTC1 = 0x60,
+ CEIL_W = 0x6c,
+ MFC1 = 0x80,
+ CVT_S_PL = 0x84,
+ TRUNC_L = 0x8c,
+ MTC1 = 0xa0,
+ CVT_S_PU = 0xa4,
+ TRUNC_W = 0xac,
+ MFHC1 = 0xc0,
+ ROUND_L = 0xcc,
+ MTHC1 = 0xe0,
+ ROUND_W = 0xec,
+
+ MOV_FMT = 0x01,
+ MOVF = 0x05,
+ ABS_FMT = 0x0d,
+ RSQRT1_FMT = 0x1d,
+ MOVT = 0x25,
+ NEG_FMT = 0x2d,
+ CVT_D = 0x4d,
+ RECIP1_FMT = 0x5d,
+ CVT_S = 0x6d
+};
+
+/* POOL32I encoding of minor opcode field (bits 25..21) */
+
+enum {
+ BLTZ = 0x00,
+ BLTZAL = 0x01,
+ BGEZ = 0x02,
+ BGEZAL = 0x03,
+ BLEZ = 0x04,
+ BNEZC = 0x05,
+ BGTZ = 0x06,
+ BEQZC = 0x07,
+ TLTI = 0x08,
+ TGEI = 0x09,
+ TLTIU = 0x0a,
+ TGEIU = 0x0b,
+ TNEI = 0x0c,
+ LUI = 0x0d,
+ TEQI = 0x0e,
+ SYNCI = 0x10,
+ BLTZALS = 0x11,
+ BGEZALS = 0x13,
+ BC2F = 0x14,
+ BC2T = 0x15,
+ BPOSGE64 = 0x1a,
+ BPOSGE32 = 0x1b,
+ /* These overlap and are distinguished by bit16 of the instruction */
+ BC1F = 0x1c,
+ BC1T = 0x1d,
+ BC1ANY2F = 0x1c,
+ BC1ANY2T = 0x1d,
+ BC1ANY4F = 0x1e,
+ BC1ANY4T = 0x1f
+};
+
+/* POOL16A encoding of minor opcode field */
+
+enum {
+ ADDU16 = 0x0,
+ SUBU16 = 0x1
+};
+
+/* POOL16B encoding of minor opcode field */
+
+enum {
+ SLL16 = 0x0,
+ SRL16 = 0x1
+};
+
+/* POOL16C encoding of minor opcode field */
+
+enum {
+ NOT16 = 0x00,
+ XOR16 = 0x04,
+ AND16 = 0x08,
+ OR16 = 0x0c,
+ LWM16 = 0x10,
+ SWM16 = 0x14,
+ JR16 = 0x18,
+ JRC16 = 0x1a,
+ JALR16 = 0x1c,
+ JALR16S = 0x1e,
+ MFHI16 = 0x20,
+ MFLO16 = 0x24,
+ BREAK16 = 0x28,
+ SDBBP16 = 0x2c,
+ JRADDIUSP = 0x30
+};
+
+/* POOL16D encoding of minor opcode field */
+
+enum {
+ ADDIUS5 = 0x0,
+ ADDIUSP = 0x1
+};
+
+/* POOL16E encoding of minor opcode field */
+
+enum {
+ ADDIUR2 = 0x0,
+ ADDIUR1SP = 0x1
+};
+
+static int mmreg (int r)
+{
+ static const int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 };
+
+ return map[r];
+}
+
+/* Used for 16-bit store instructions. */
+static int mmreg2 (int r)
+{
+ static const int map[] = { 0, 17, 2, 3, 4, 5, 6, 7 };
+
+ return map[r];
+}
+
+#define uMIPS_RD(op) ((op >> 7) & 0x7)
+#define uMIPS_RS(op) ((op >> 4) & 0x7)
+#define uMIPS_RS2(op) uMIPS_RS(op)
+#define uMIPS_RS1(op) ((op >> 1) & 0x7)
+#define uMIPS_RD5(op) ((op >> 5) & 0x1f)
+#define uMIPS_RS5(op) (op & 0x1f)
+
+/* Signed immediate */
+#define SIMM(op, start, width) \
+ ((int32_t)(((op >> start) & ((~0U) >> (32-width))) \
+ << (32-width)) \
+ >> (32-width))
+/* Zero-extended immediate */
+#define ZIMM(op, start, width) ((op >> start) & ((~0U) >> (32-width)))
+
+static void gen_addiur1sp (CPUState *env, DisasContext *ctx)
+{
+ int rd = mmreg(uMIPS_RD(ctx->opcode));
+
+ gen_arith_imm(env, ctx, OPC_ADDIU, rd, 29, ((ctx->opcode >> 1) & 0x3f) << 2);
+}
+
+static void gen_addiur2 (CPUState *env, DisasContext *ctx)
+{
+ static const int decoded_imm[] = { 1, 4, 8, 12, 16, 20, 24, -1 };
+ int rd = mmreg(uMIPS_RD(ctx->opcode));
+ int rs = mmreg(uMIPS_RS(ctx->opcode));
+
+ gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, decoded_imm[ZIMM(ctx->opcode, 1, 3)]);
+}
+
+static void gen_addiusp (CPUState *env, DisasContext *ctx)
+{
+ int encoded = ZIMM(ctx->opcode, 1, 9);
+ int decoded;
+
+ if (encoded <= 1) {
+ decoded = 256 + encoded;
+ } else if (encoded <= 255) {
+ decoded = encoded;
+ } else if (encoded <= 509) {
+ decoded = encoded - 512;
+ } else {
+ decoded = encoded - 768;
+ }
+
+ gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, decoded << 2);
+}
+
+static void gen_addius5 (CPUState *env, DisasContext *ctx)
+{
+ int imm = SIMM(ctx->opcode, 1, 4);
+ int rd = (ctx->opcode >> 5) & 0x1f;
+
+ gen_arith_imm(env, ctx, OPC_ADDIU, rd, rd, imm);
+}
+
+static void gen_andi16 (CPUState *env, DisasContext *ctx)
+{
+ static const int decoded_imm[] = { 128, 1, 2, 3, 4, 7, 8, 15, 16,
+ 31, 32, 63, 64, 255, 32768, 65535 };
+ int rd = mmreg(uMIPS_RD(ctx->opcode));
+ int rs = mmreg(uMIPS_RS(ctx->opcode));
+ int encoded = ZIMM(ctx->opcode, 0, 4);
+
+ gen_logic_imm(env, OPC_ANDI, rd, rs, decoded_imm[encoded]);
+}
+
+static void gen_ldst_multiple (DisasContext *ctx, uint32_t opc, int reglist,
+ int base, int16_t offset)
+{
+ TCGv t0, t1;
+ TCGv_i32 t2;
+
+ if (ctx->hflags & MIPS_HFLAG_BMASK) {
+ generate_exception(ctx, EXCP_RI);
+ return;
+ }
+
+ t0 = tcg_temp_new();
+
+ gen_base_offset_addr(ctx, t0, base, offset);
+
+ t1 = tcg_const_tl(reglist);
+ t2 = tcg_const_i32(ctx->mem_idx);
+
+ save_cpu_state(ctx, 1);
+ switch (opc) {
+ case LWM32:
+ gen_helper_lwm(t0, t1, t2);
+ break;
+ case SWM32:
+ gen_helper_swm(t0, t1, t2);
+ break;
+#ifdef TARGET_MIPS64
+ case LDM:
+ gen_helper_ldm(t0, t1, t2);
+ break;
+ case SDM:
+ gen_helper_sdm(t0, t1, t2);
+ break;
+#endif
+ }
+ MIPS_DEBUG("%s, %x, %d(%s)", opn, reglist, offset, regnames[base]);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+ tcg_temp_free_i32(t2);
+}
+
+
+static void gen_pool16c_insn (CPUState *env, DisasContext *ctx, int *is_branch)
+{
+ int rd = mmreg((ctx->opcode >> 3) & 0x7);
+ int rs = mmreg(ctx->opcode & 0x7);
+ int opc;
+
+ switch (((ctx->opcode) >> 4) & 0x3f) {
+ case NOT16 + 0:
+ case NOT16 + 1:
+ case NOT16 + 2:
+ case NOT16 + 3:
+ gen_logic(env, OPC_NOR, rd, rs, 0);
+ break;
+ case XOR16 + 0:
+ case XOR16 + 1:
+ case XOR16 + 2:
+ case XOR16 + 3:
+ gen_logic(env, OPC_XOR, rd, rd, rs);
+ break;
+ case AND16 + 0:
+ case AND16 + 1:
+ case AND16 + 2:
+ case AND16 + 3:
+ gen_logic(env, OPC_AND, rd, rd, rs);
+ break;
+ case OR16 + 0:
+ case OR16 + 1:
+ case OR16 + 2:
+ case OR16 + 3:
+ gen_logic(env, OPC_OR, rd, rd, rs);
+ break;
+ case LWM16 + 0:
+ case LWM16 + 1:
+ case LWM16 + 2:
+ case LWM16 + 3:
+ {
+ static const int lwm_convert[] = { 0x11, 0x12, 0x13, 0x14 };
+ int offset = ZIMM(ctx->opcode, 0, 4);
+
+ gen_ldst_multiple(ctx, LWM32, lwm_convert[(ctx->opcode >> 4) & 0x3],
+ 29, offset << 2);
+ }
+ break;
+ case SWM16 + 0:
+ case SWM16 + 1:
+ case SWM16 + 2:
+ case SWM16 + 3:
+ {
+ static const int swm_convert[] = { 0x11, 0x12, 0x13, 0x14 };
+ int offset = ZIMM(ctx->opcode, 0, 4);
+
+ gen_ldst_multiple(ctx, SWM32, swm_convert[(ctx->opcode >> 4) & 0x3],
+ 29, offset << 2);
+ }
+ break;
+ case JR16 + 0:
+ case JR16 + 1:
+ {
+ int reg = ctx->opcode & 0x1f;
+
+ gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0);
+ }
+ *is_branch = 1;
+ break;
+ case JRC16 + 0:
+ case JRC16 + 1:
+ {
+ int reg = ctx->opcode & 0x1f;
+
+ gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0);
+ /* Let normal delay slot handling in our caller take us
+ to the branch target. */
+ }
+ break;
+ case JALR16 + 0:
+ case JALR16 + 1:
+ opc = OPC_JALR;
+ goto do_jalr;
+ case JALR16S + 0:
+ case JALR16S + 1:
+ opc = OPC_JALRS;
+ do_jalr:
+ {
+ int reg = ctx->opcode & 0x1f;
+
+ gen_compute_branch(ctx, opc, 2, reg, 31, 0);
+ }
+ *is_branch = 1;
+ break;
+ case MFHI16 + 0:
+ case MFHI16 + 1:
+ gen_HILO(ctx, OPC_MFHI, uMIPS_RS5(ctx->opcode));
+ break;
+ case MFLO16 + 0:
+ case MFLO16 + 1:
+ gen_HILO(ctx, OPC_MFLO, uMIPS_RS5(ctx->opcode));
+ break;
+ case BREAK16:
+ generate_exception(ctx, EXCP_BREAK);
+ break;
+ case SDBBP16:
+ /* XXX: not clear which exception should be raised
+ * when in debug mode...
+ */
+ check_insn(env, ctx, ISA_MIPS32);
+ if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+ generate_exception(ctx, EXCP_DBp);
+ } else {
+ generate_exception(ctx, EXCP_DBp);
+ }
+ break;
+ case JRADDIUSP + 0:
+ case JRADDIUSP + 1:
+ {
+ int imm = ZIMM(ctx->opcode, 0, 5);
+
+ gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0);
+ gen_arith_imm(env, ctx, OPC_ADDIU, 29, 29, imm << 2);
+ /* Let normal delay slot handling in our caller take us
+ to the branch target. */
+ }
+ break;
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+}
+
+static void gen_ldxs (DisasContext *ctx, int base, int index, int rd)
+{
+ TCGv t0 = tcg_temp_new();
+ TCGv t1 = tcg_temp_new();
+
+ gen_load_gpr(t0, base);
+
+ if (index != 0) {
+ gen_load_gpr(t1, index);
+ tcg_gen_shli_tl(t1, t1, 2);
+ gen_op_addr_add(ctx, t0, t1, t0);
+ }
+
+ save_cpu_state(ctx, 0);
+ op_ldst_lw(t1, t0, ctx);
+ gen_store_gpr(t1, rd);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+}
+
+static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
+ int base, int16_t offset)
+{
+ const char *opn = "ldst_pair";
+ TCGv t0, t1;
+
+ if (ctx->hflags & MIPS_HFLAG_BMASK || rd == 31 || rd == base) {
+ generate_exception(ctx, EXCP_RI);
+ return;
+ }
+
+ t0 = tcg_temp_new();
+ t1 = tcg_temp_new();
+
+ gen_base_offset_addr(ctx, t0, base, offset);
+
+ switch (opc) {
+ case LWP:
+ save_cpu_state(ctx, 0);
+ op_ldst_lw(t1, t0, ctx);
+ gen_store_gpr(t1, rd);
+ tcg_gen_movi_tl(t1, 4);
+ gen_op_addr_add(ctx, t0, t0, t1);
+ op_ldst_lw(t1, t0, ctx);
+ gen_store_gpr(t1, rd+1);
+ opn = "lwp";
+ break;
+ case SWP:
+ save_cpu_state(ctx, 1);
+ gen_load_gpr(t1, rd);
+ op_ldst_sw(t1, t0, ctx);
+ tcg_gen_movi_tl(t1, 4);
+ gen_op_addr_add(ctx, t0, t0, t1);
+ gen_load_gpr(t1, rd+1);
+ op_ldst_sw(t1, t0, ctx);
+ opn = "swp";
+ break;
+#ifdef TARGET_MIPS64
+ case LDP:
+ save_cpu_state(ctx, 0);
+ op_ldst_ld(t1, t0, ctx);
+ gen_store_gpr(t1, rd);
+ tcg_gen_movi_tl(t1, 8);
+ gen_op_addr_add(ctx, t0, t0, t1);
+ op_ldst_ld(t1, t0, ctx);
+ gen_store_gpr(t1, rd+1);
+ opn = "ldp";
+ break;
+ case SDP:
+ save_cpu_state(ctx, 1);
+ gen_load_gpr(t1, rd);
+ op_ldst_sd(t1, t0, ctx);
+ tcg_gen_movi_tl(t1, 8);
+ gen_op_addr_add(ctx, t0, t0, t1);
+ gen_load_gpr(t1, rd+1);
+ op_ldst_sd(t1, t0, ctx);
+ opn = "sdp";
+ break;
+#endif
+ }
+ MIPS_DEBUG("%s, %s, %d(%s)", opn, regnames[rd], offset, regnames[base]);
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
+}
+
+static void gen_pool32axf (CPUState *env, DisasContext *ctx, int rt, int rs,
+ int *is_branch)
+{
+ int extension = (ctx->opcode >> 6) & 0x3f;
+ int minor = (ctx->opcode >> 12) & 0xf;
+ uint32_t mips32_op;
+
+ switch (extension) {
+ case TEQ:
+ mips32_op = OPC_TEQ;
+ goto do_trap;
+ case TGE:
+ mips32_op = OPC_TGE;
+ goto do_trap;
+ case TGEU:
+ mips32_op = OPC_TGEU;
+ goto do_trap;
+ case TLT:
+ mips32_op = OPC_TLT;
+ goto do_trap;
+ case TLTU:
+ mips32_op = OPC_TLTU;
+ goto do_trap;
+ case TNE:
+ mips32_op = OPC_TNE;
+ do_trap:
+ gen_trap(ctx, mips32_op, rs, rt, -1);
+ break;
+#ifndef CONFIG_USER_ONLY
+ case MFC0:
+ case MFC0 + 32:
+ if (rt == 0) {
+ /* Treat as NOP. */
+ break;
+ }
+ gen_mfc0(env, ctx, cpu_gpr[rt], rs, (ctx->opcode >> 11) & 0x7);
+ break;
+ case MTC0:
+ case MTC0 + 32:
+ {
+ TCGv t0 = tcg_temp_new();
+
+ gen_load_gpr(t0, rt);
+ gen_mtc0(env, ctx, t0, rs, (ctx->opcode >> 11) & 0x7);
+ tcg_temp_free(t0);
+ }
+ break;
+#endif
+ case 0x2c:
+ switch (minor) {
+ case SEB:
+ gen_bshfl(ctx, OPC_SEB, rs, rt);
+ break;
+ case SEH:
+ gen_bshfl(ctx, OPC_SEH, rs, rt);
+ break;
+ case CLO:
+ mips32_op = OPC_CLO;
+ goto do_cl;
+ case CLZ:
+ mips32_op = OPC_CLZ;
+ do_cl:
+ check_insn(env, ctx, ISA_MIPS32);
+ gen_cl(ctx, mips32_op, rt, rs);
+ break;
+ case RDHWR:
+ gen_rdhwr(env, ctx, rt, rs);
+ break;
+ case WSBH:
+ gen_bshfl(ctx, OPC_WSBH, rs, rt);
+ break;
+ case MULT:
+ mips32_op = OPC_MULT;
+ goto do_muldiv;
+ case MULTU:
+ mips32_op = OPC_MULTU;
+ goto do_muldiv;
+ case DIV:
+ mips32_op = OPC_DIV;
+ goto do_muldiv;
+ case DIVU:
+ mips32_op = OPC_DIVU;
+ goto do_muldiv;
+ case MADD:
+ mips32_op = OPC_MADD;
+ goto do_muldiv;
+ case MADDU:
+ mips32_op = OPC_MADDU;
+ goto do_muldiv;
+ case MSUB:
+ mips32_op = OPC_MSUB;
+ goto do_muldiv;
+ case MSUBU:
+ mips32_op = OPC_MSUBU;
+ do_muldiv:
+ check_insn(env, ctx, ISA_MIPS32);
+ gen_muldiv(ctx, mips32_op, rs, rt);
+ break;
+ default:
+ goto pool32axf_invalid;
+ }
+ break;
+ case 0x34:
+ switch (minor) {
+ case MFC2:
+ case MTC2:
+ case MFHC2:
+ case MTHC2:
+ case CFC2:
+ case CTC2:
+ generate_exception_err(ctx, EXCP_CpU, 2);
+ break;
+ default:
+ goto pool32axf_invalid;
+ }
+ break;
+ case 0x3c:
+ switch (minor) {
+ case JALR:
+ case JALR_HB:
+ gen_compute_branch (ctx, OPC_JALR, 4, rs, rt, 0);
+ *is_branch = 1;
+ break;
+ case JALRS:
+ case JALRS_HB:
+ gen_compute_branch (ctx, OPC_JALRS, 4, rs, rt, 0);
+ *is_branch = 1;
+ break;
+ default:
+ goto pool32axf_invalid;
+ }
+ break;
+ case 0x05:
+ switch (minor) {
+ case RDPGPR:
+ check_insn(env, ctx, ISA_MIPS32R2);
+ gen_load_srsgpr(rt, rs);
+ break;
+ case WRPGPR:
+ check_insn(env, ctx, ISA_MIPS32R2);
+ gen_store_srsgpr(rt, rs);
+ break;
+ default:
+ goto pool32axf_invalid;
+ }
+ break;
+#ifndef CONFIG_USER_ONLY
+ case 0x0d:
+ switch (minor) {
+ case TLBP:
+ mips32_op = OPC_TLBP;
+ goto do_cp0;
+ case TLBR:
+ mips32_op = OPC_TLBR;
+ goto do_cp0;
+ case TLBWI:
+ mips32_op = OPC_TLBWI;
+ goto do_cp0;
+ case TLBWR:
+ mips32_op = OPC_TLBWR;
+ goto do_cp0;
+ case WAIT:
+ mips32_op = OPC_WAIT;
+ goto do_cp0;
+ case DERET:
+ mips32_op = OPC_DERET;
+ goto do_cp0;
+ case ERET:
+ mips32_op = OPC_ERET;
+ do_cp0:
+ gen_cp0(env, ctx, mips32_op, rt, rs);
+ break;
+ default:
+ goto pool32axf_invalid;
+ }
+ break;
+ case 0x1d:
+ switch (minor) {
+ case DI:
+ {
+ TCGv t0 = tcg_temp_new();
+
+ save_cpu_state(ctx, 1);
+ gen_helper_di(t0);
+ gen_store_gpr(t0, rs);
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
+ tcg_temp_free(t0);
+ }
+ break;
+ case EI:
+ {
+ TCGv t0 = tcg_temp_new();
+
+ save_cpu_state(ctx, 1);
+ gen_helper_ei(t0);
+ gen_store_gpr(t0, rs);
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
+ tcg_temp_free(t0);
+ }
+ break;
+ default:
+ goto pool32axf_invalid;
+ }
+ break;
+#endif
+ case 0x2d:
+ switch (minor) {
+ case SYNC:
+ /* NOP */
+ break;
+ case SYSCALL:
+ generate_exception(ctx, EXCP_SYSCALL);
+ ctx->bstate = BS_STOP;
+ break;
+ case SDBBP:
+ check_insn(env, ctx, ISA_MIPS32);
+ if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+ generate_exception(ctx, EXCP_DBp);
+ } else {
+ generate_exception(ctx, EXCP_DBp);
+ }
+ break;
+ default:
+ goto pool32axf_invalid;
+ }
+ break;
+ case 0x35:
+ switch (minor) {
+ case MFHI32:
+ gen_HILO(ctx, OPC_MFHI, rs);
+ break;
+ case MFLO32:
+ gen_HILO(ctx, OPC_MFLO, rs);
+ break;
+ case MTHI32:
+ gen_HILO(ctx, OPC_MTHI, rs);
+ break;
+ case MTLO32:
+ gen_HILO(ctx, OPC_MTLO, rs);
+ break;
+ default:
+ goto pool32axf_invalid;
+ }
+ break;
+ default:
+ pool32axf_invalid:
+ MIPS_INVAL("pool32axf");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+}
+
+/* Values for microMIPS fmt field. Variable-width, depending on which
+ formats the instruction supports. */
+
+enum {
+ FMT_SD_S = 0,
+ FMT_SD_D = 1,
+
+ FMT_SDPS_S = 0,
+ FMT_SDPS_D = 1,
+ FMT_SDPS_PS = 2,
+
+ FMT_SWL_S = 0,
+ FMT_SWL_W = 1,
+ FMT_SWL_L = 2,
+
+ FMT_DWL_D = 0,
+ FMT_DWL_W = 1,
+ FMT_DWL_L = 2
+};
+
+static void gen_pool32fxf (CPUState *env, DisasContext *ctx, int rt, int rs)
+{
+ int extension = (ctx->opcode >> 6) & 0x3ff;
+ uint32_t mips32_op;
+
+#define FLOAT_1BIT_FMT(opc, fmt) (fmt << 8) | opc
+#define FLOAT_2BIT_FMT(opc, fmt) (fmt << 7) | opc
+#define COND_FLOAT_MOV(opc, cond) (cond << 7) | opc
+
+ switch (extension) {
+ case FLOAT_1BIT_FMT(CFC1, 0):
+ mips32_op = OPC_CFC1;
+ goto do_cp1;
+ case FLOAT_1BIT_FMT(CTC1, 0):
+ mips32_op = OPC_CTC1;
+ goto do_cp1;
+ case FLOAT_1BIT_FMT(MFC1, 0):
+ mips32_op = OPC_MFC1;
+ goto do_cp1;
+ case FLOAT_1BIT_FMT(MTC1, 0):
+ mips32_op = OPC_MTC1;
+ goto do_cp1;
+ case FLOAT_1BIT_FMT(MFHC1, 0):
+ mips32_op = OPC_MFHC1;
+ goto do_cp1;
+ case FLOAT_1BIT_FMT(MTHC1, 0):
+ mips32_op = OPC_MTHC1;
+ do_cp1:
+ gen_cp1(ctx, mips32_op, rt, rs);
+ break;
+
+ /* Reciprocal square root */
+ case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_S):
+ mips32_op = OPC_RSQRT_S;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_D):
+ mips32_op = OPC_RSQRT_D;
+ goto do_unaryfp;
+
+ /* Square root */
+ case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_S):
+ mips32_op = OPC_SQRT_S;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_D):
+ mips32_op = OPC_SQRT_D;
+ goto do_unaryfp;
+
+ /* Reciprocal */
+ case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_S):
+ mips32_op = OPC_RECIP_S;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_D):
+ mips32_op = OPC_RECIP_D;
+ goto do_unaryfp;
+
+ /* Floor */
+ case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_S):
+ mips32_op = OPC_FLOOR_L_S;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_D):
+ mips32_op = OPC_FLOOR_L_D;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_S):
+ mips32_op = OPC_FLOOR_W_S;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_D):
+ mips32_op = OPC_FLOOR_W_D;
+ goto do_unaryfp;
+
+ /* Ceiling */
+ case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_S):
+ mips32_op = OPC_CEIL_L_S;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_D):
+ mips32_op = OPC_CEIL_L_D;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_S):
+ mips32_op = OPC_CEIL_W_S;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_D):
+ mips32_op = OPC_CEIL_W_D;
+ goto do_unaryfp;
+
+ /* Truncation */
+ case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_S):
+ mips32_op = OPC_TRUNC_L_S;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_D):
+ mips32_op = OPC_TRUNC_L_D;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_S):
+ mips32_op = OPC_TRUNC_W_S;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_D):
+ mips32_op = OPC_TRUNC_W_D;
+ goto do_unaryfp;
+
+ /* Round */
+ case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_S):
+ mips32_op = OPC_ROUND_L_S;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_D):
+ mips32_op = OPC_ROUND_L_D;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_S):
+ mips32_op = OPC_ROUND_W_S;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_D):
+ mips32_op = OPC_ROUND_W_D;
+ goto do_unaryfp;
+
+ /* Integer to floating-point conversion */
+ case FLOAT_1BIT_FMT(CVT_L, FMT_SD_S):
+ mips32_op = OPC_CVT_L_S;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(CVT_L, FMT_SD_D):
+ mips32_op = OPC_CVT_L_D;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(CVT_W, FMT_SD_S):
+ mips32_op = OPC_CVT_W_S;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(CVT_W, FMT_SD_D):
+ mips32_op = OPC_CVT_W_D;
+ goto do_unaryfp;
+
+ /* Paired-foo conversions */
+ case FLOAT_1BIT_FMT(CVT_S_PL, 0):
+ mips32_op = OPC_CVT_S_PL;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(CVT_S_PU, 0):
+ mips32_op = OPC_CVT_S_PU;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(CVT_PW_PS, 0):
+ mips32_op = OPC_CVT_PW_PS;
+ goto do_unaryfp;
+ case FLOAT_1BIT_FMT(CVT_PS_PW, 0):
+ mips32_op = OPC_CVT_PS_PW;
+ goto do_unaryfp;
+
+ /* Floating-point moves */
+ case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_S):
+ mips32_op = OPC_MOV_S;
+ goto do_unaryfp;
+ case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_D):
+ mips32_op = OPC_MOV_D;
+ goto do_unaryfp;
+ case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_PS):
+ mips32_op = OPC_MOV_PS;
+ goto do_unaryfp;
+
+ /* Absolute value */
+ case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_S):
+ mips32_op = OPC_ABS_S;
+ goto do_unaryfp;
+ case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_D):
+ mips32_op = OPC_ABS_D;
+ goto do_unaryfp;
+ case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_PS):
+ mips32_op = OPC_ABS_PS;
+ goto do_unaryfp;
+
+ /* Negation */
+ case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_S):
+ mips32_op = OPC_NEG_S;
+ goto do_unaryfp;
+ case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_D):
+ mips32_op = OPC_NEG_D;
+ goto do_unaryfp;
+ case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_PS):
+ mips32_op = OPC_NEG_PS;
+ goto do_unaryfp;
+
+ /* Reciprocal square root step */
+ case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_S):
+ mips32_op = OPC_RSQRT1_S;
+ goto do_unaryfp;
+ case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_D):
+ mips32_op = OPC_RSQRT1_D;
+ goto do_unaryfp;
+ case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_PS):
+ mips32_op = OPC_RSQRT1_PS;
+ goto do_unaryfp;
+
+ /* Reciprocal step */
+ case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_S):
+ mips32_op = OPC_RECIP1_S;
+ goto do_unaryfp;
+ case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_D):
+ mips32_op = OPC_RECIP1_S;
+ goto do_unaryfp;
+ case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_PS):
+ mips32_op = OPC_RECIP1_PS;
+ goto do_unaryfp;
+
+ /* Conversions from double */
+ case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_S):
+ mips32_op = OPC_CVT_D_S;
+ goto do_unaryfp;
+ case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_W):
+ mips32_op = OPC_CVT_D_W;
+ goto do_unaryfp;
+ case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_L):
+ mips32_op = OPC_CVT_D_L;
+ goto do_unaryfp;
+
+ /* Conversions from single */
+ case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_D):
+ mips32_op = OPC_CVT_S_D;
+ goto do_unaryfp;
+ case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_W):
+ mips32_op = OPC_CVT_S_W;
+ goto do_unaryfp;
+ case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_L):
+ mips32_op = OPC_CVT_S_L;
+ do_unaryfp:
+ gen_farith(ctx, mips32_op, -1, rs, rt, 0);
+ break;
+
+ /* Conditional moves on floating-point codes */
+ case COND_FLOAT_MOV(MOVT, 0):
+ case COND_FLOAT_MOV(MOVT, 1):
+ case COND_FLOAT_MOV(MOVT, 2):
+ case COND_FLOAT_MOV(MOVT, 3):
+ case COND_FLOAT_MOV(MOVT, 4):
+ case COND_FLOAT_MOV(MOVT, 5):
+ case COND_FLOAT_MOV(MOVT, 6):
+ case COND_FLOAT_MOV(MOVT, 7):
+ gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 1);
+ break;
+ case COND_FLOAT_MOV(MOVF, 0):
+ case COND_FLOAT_MOV(MOVF, 1):
+ case COND_FLOAT_MOV(MOVF, 2):
+ case COND_FLOAT_MOV(MOVF, 3):
+ case COND_FLOAT_MOV(MOVF, 4):
+ case COND_FLOAT_MOV(MOVF, 5):
+ case COND_FLOAT_MOV(MOVF, 6):
+ case COND_FLOAT_MOV(MOVF, 7):
+ gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 0);
+ break;
+ default:
+ MIPS_INVAL("pool32fxf");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+}
+
+static void decode_micromips32_opc (CPUState *env, DisasContext *ctx,
+ uint16_t insn_hw1, int *is_branch)
+{
+ int32_t offset;
+ uint16_t insn;
+ int rt, rs, rd, rr;
+ int16_t imm;
+ uint32_t op, minor, mips32_op;
+ uint32_t cond, fmt, cc;
+
+ insn = lduw_code(ctx->pc + 2);
+ ctx->opcode = (ctx->opcode << 16) | insn;
+
+ rt = (ctx->opcode >> 21) & 0x1f;
+ rs = (ctx->opcode >> 16) & 0x1f;
+ rd = (ctx->opcode >> 11) & 0x1f;
+ rr = (ctx->opcode >> 6) & 0x1f;
+ imm = (int16_t) ctx->opcode;
+
+ op = (ctx->opcode >> 26) & 0x3f;
+ switch (op) {
+ case POOL32A:
+ minor = ctx->opcode & 0x3f;
+ switch (minor) {
+ case 0x00:
+ minor = (ctx->opcode >> 6) & 0xf;
+ switch (minor) {
+ case SLL32:
+ mips32_op = OPC_SLL;
+ goto do_shifti;
+ case SRA:
+ mips32_op = OPC_SRA;
+ goto do_shifti;
+ case SRL32:
+ mips32_op = OPC_SRL;
+ goto do_shifti;
+ case ROTR:
+ mips32_op = OPC_ROTR;
+ do_shifti:
+ gen_shift_imm(env, ctx, mips32_op, rt, rs, rd);
+ break;
+ default:
+ goto pool32a_invalid;
+ }
+ break;
+ case 0x10:
+ minor = (ctx->opcode >> 6) & 0xf;
+ switch (minor) {
+ /* Arithmetic */
+ case ADD:
+ mips32_op = OPC_ADD;
+ goto do_arith;
+ case ADDU32:
+ mips32_op = OPC_ADDU;
+ goto do_arith;
+ case SUB:
+ mips32_op = OPC_SUB;
+ goto do_arith;
+ case SUBU32:
+ mips32_op = OPC_SUBU;
+ goto do_arith;
+ case MUL:
+ mips32_op = OPC_MUL;
+ do_arith:
+ gen_arith(env, ctx, mips32_op, rd, rs, rt);
+ break;
+ /* Shifts */
+ case SLLV:
+ mips32_op = OPC_SLLV;
+ goto do_shift;
+ case SRLV:
+ mips32_op = OPC_SRLV;
+ goto do_shift;
+ case SRAV:
+ mips32_op = OPC_SRAV;
+ goto do_shift;
+ case ROTRV:
+ mips32_op = OPC_ROTRV;
+ do_shift:
+ gen_shift(env, ctx, mips32_op, rd, rs, rt);
+ break;
+ /* Logical operations */
+ case AND:
+ mips32_op = OPC_AND;
+ goto do_logic;
+ case OR32:
+ mips32_op = OPC_OR;
+ goto do_logic;
+ case NOR:
+ mips32_op = OPC_NOR;
+ goto do_logic;
+ case XOR32:
+ mips32_op = OPC_XOR;
+ do_logic:
+ gen_logic(env, mips32_op, rd, rs, rt);
+ break;
+ /* Set less than */
+ case SLT:
+ mips32_op = OPC_SLT;
+ goto do_slt;
+ case SLTU:
+ mips32_op = OPC_SLTU;
+ do_slt:
+ gen_slt(env, mips32_op, rd, rs, rt);
+ break;
+ default:
+ goto pool32a_invalid;
+ }
+ break;
+ case 0x18:
+ minor = (ctx->opcode >> 6) & 0xf;
+ switch (minor) {
+ /* Conditional moves */
+ case MOVN:
+ mips32_op = OPC_MOVN;
+ goto do_cmov;
+ case MOVZ:
+ mips32_op = OPC_MOVZ;
+ do_cmov:
+ gen_cond_move(env, mips32_op, rd, rs, rt);
+ break;
+ case LWXS:
+ gen_ldxs(ctx, rs, rt, rd);
+ break;
+ default:
+ goto pool32a_invalid;
+ }
+ break;
+ case INS:
+ gen_bitops(ctx, OPC_INS, rt, rs, rr, rd);
+ return;
+ case EXT:
+ gen_bitops(ctx, OPC_EXT, rt, rs, rr, rd);
+ return;
+ case POOL32AXF:
+ gen_pool32axf(env, ctx, rt, rs, is_branch);
+ break;
+ case 0x07:
+ generate_exception(ctx, EXCP_BREAK);
+ break;
+ default:
+ pool32a_invalid:
+ MIPS_INVAL("pool32a");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
+ case POOL32B:
+ minor = (ctx->opcode >> 12) & 0xf;
+ switch (minor) {
+ case CACHE:
+ /* Treat as no-op. */
+ break;
+ case LWC2:
+ case SWC2:
+ /* COP2: Not implemented. */
+ generate_exception_err(ctx, EXCP_CpU, 2);
+ break;
+ case LWP:
+ case SWP:
+#ifdef TARGET_MIPS64
+ case LDP:
+ case SDP:
+#endif
+ gen_ldst_pair(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12));
+ break;
+ case LWM32:
+ case SWM32:
+#ifdef TARGET_MIPS64
+ case LDM:
+ case SDM:
+#endif
+ gen_ldst_multiple(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12));
+ break;
+ default:
+ MIPS_INVAL("pool32b");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
+ case POOL32F:
+ if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+ minor = ctx->opcode & 0x3f;
+ check_cp1_enabled(ctx);
+ switch (minor) {
+ case ALNV_PS:
+ mips32_op = OPC_ALNV_PS;
+ goto do_madd;
+ case MADD_S:
+ mips32_op = OPC_MADD_S;
+ goto do_madd;
+ case MADD_D:
+ mips32_op = OPC_MADD_D;
+ goto do_madd;
+ case MADD_PS:
+ mips32_op = OPC_MADD_PS;
+ goto do_madd;
+ case MSUB_S:
+ mips32_op = OPC_MSUB_S;
+ goto do_madd;
+ case MSUB_D:
+ mips32_op = OPC_MSUB_D;
+ goto do_madd;
+ case MSUB_PS:
+ mips32_op = OPC_MSUB_PS;
+ goto do_madd;
+ case NMADD_S:
+ mips32_op = OPC_NMADD_S;
+ goto do_madd;
+ case NMADD_D:
+ mips32_op = OPC_NMADD_D;
+ goto do_madd;
+ case NMADD_PS:
+ mips32_op = OPC_NMADD_PS;
+ goto do_madd;
+ case NMSUB_S:
+ mips32_op = OPC_NMSUB_S;
+ goto do_madd;
+ case NMSUB_D:
+ mips32_op = OPC_NMSUB_D;
+ goto do_madd;
+ case NMSUB_PS:
+ mips32_op = OPC_NMSUB_PS;
+ do_madd:
+ gen_flt3_arith(ctx, mips32_op, rd, rr, rs, rt);
+ break;
+ case CABS_COND_FMT:
+ cond = (ctx->opcode >> 6) & 0xf;
+ cc = (ctx->opcode >> 13) & 0x7;
+ fmt = (ctx->opcode >> 10) & 0x3;
+ switch (fmt) {
+ case 0x0:
+ gen_cmpabs_s(ctx, cond, rt, rs, cc);
+ break;
+ case 0x1:
+ gen_cmpabs_d(ctx, cond, rt, rs, cc);
+ break;
+ case 0x2:
+ gen_cmpabs_ps(ctx, cond, rt, rs, cc);
+ break;
+ default:
+ goto pool32f_invalid;
+ }
+ break;
+ case C_COND_FMT:
+ cond = (ctx->opcode >> 6) & 0xf;
+ cc = (ctx->opcode >> 13) & 0x7;
+ fmt = (ctx->opcode >> 10) & 0x3;
+ switch (fmt) {
+ case 0x0:
+ gen_cmp_s(ctx, cond, rt, rs, cc);
+ break;
+ case 0x1:
+ gen_cmp_d(ctx, cond, rt, rs, cc);
+ break;
+ case 0x2:
+ gen_cmp_ps(ctx, cond, rt, rs, cc);
+ break;
+ default:
+ goto pool32f_invalid;
+ }
+ break;
+ case POOL32FXF:
+ gen_pool32fxf(env, ctx, rt, rs);
+ break;
+ case 0x00:
+ /* PLL foo */
+ switch ((ctx->opcode >> 6) & 0x7) {
+ case PLL_PS:
+ mips32_op = OPC_PLL_PS;
+ goto do_ps;
+ case PLU_PS:
+ mips32_op = OPC_PLU_PS;
+ goto do_ps;
+ case PUL_PS:
+ mips32_op = OPC_PUL_PS;
+ goto do_ps;
+ case PUU_PS:
+ mips32_op = OPC_PUU_PS;
+ goto do_ps;
+ case CVT_PS_S:
+ mips32_op = OPC_CVT_PS_S;
+ do_ps:
+ gen_farith(ctx, mips32_op, rt, rs, rd, 0);
+ break;
+ default:
+ goto pool32f_invalid;
+ }
+ break;
+ case 0x08:
+ /* [LS][WDU]XC1 */
+ switch ((ctx->opcode >> 6) & 0x7) {
+ case LWXC1:
+ mips32_op = OPC_LWXC1;
+ goto do_ldst_cp1;
+ case SWXC1:
+ mips32_op = OPC_SWXC1;
+ goto do_ldst_cp1;
+ case LDXC1:
+ mips32_op = OPC_LDXC1;
+ goto do_ldst_cp1;
+ case SDXC1:
+ mips32_op = OPC_SDXC1;
+ goto do_ldst_cp1;
+ case LUXC1:
+ mips32_op = OPC_LUXC1;
+ goto do_ldst_cp1;
+ case SUXC1:
+ mips32_op = OPC_SUXC1;
+ do_ldst_cp1:
+ gen_flt3_ldst(ctx, mips32_op, rd, rd, rt, rs);
+ break;
+ default:
+ goto pool32f_invalid;
+ }
+ break;
+ case 0x18:
+ /* 3D insns */
+ fmt = (ctx->opcode >> 9) & 0x3;
+ switch ((ctx->opcode >> 6) & 0x7) {
+ case RSQRT2_FMT:
+ switch (fmt) {
+ case FMT_SDPS_S:
+ mips32_op = OPC_RSQRT2_S;
+ goto do_3d;
+ case FMT_SDPS_D:
+ mips32_op = OPC_RSQRT2_D;
+ goto do_3d;
+ case FMT_SDPS_PS:
+ mips32_op = OPC_RSQRT2_PS;
+ goto do_3d;
+ default:
+ goto pool32f_invalid;
+ }
+ break;
+ case RECIP2_FMT:
+ switch (fmt) {
+ case FMT_SDPS_S:
+ mips32_op = OPC_RECIP2_S;
+ goto do_3d;
+ case FMT_SDPS_D:
+ mips32_op = OPC_RECIP2_D;
+ goto do_3d;
+ case FMT_SDPS_PS:
+ mips32_op = OPC_RECIP2_PS;
+ goto do_3d;
+ default:
+ goto pool32f_invalid;
+ }
+ break;
+ case ADDR_PS:
+ mips32_op = OPC_ADDR_PS;
+ goto do_3d;
+ case MULR_PS:
+ mips32_op = OPC_MULR_PS;
+ do_3d:
+ gen_farith(ctx, mips32_op, rt, rs, rd, 0);
+ break;
+ default:
+ goto pool32f_invalid;
+ }
+ break;
+ case 0x20:
+ /* MOV[FT].fmt and PREFX */
+ cc = (ctx->opcode >> 13) & 0x7;
+ fmt = (ctx->opcode >> 9) & 0x3;
+ switch ((ctx->opcode >> 6) & 0x7) {
+ case MOVF_FMT:
+ switch (fmt) {
+ case FMT_SDPS_S:
+ gen_movcf_s(rs, rt, cc, 0);
+ break;
+ case FMT_SDPS_D:
+ gen_movcf_d(ctx, rs, rt, cc, 0);
+ break;
+ case FMT_SDPS_PS:
+ gen_movcf_ps(rs, rt, cc, 0);
+ break;
+ default:
+ goto pool32f_invalid;
+ }
+ break;
+ case MOVT_FMT:
+ switch (fmt) {
+ case FMT_SDPS_S:
+ gen_movcf_s(rs, rt, cc, 1);
+ break;
+ case FMT_SDPS_D:
+ gen_movcf_d(ctx, rs, rt, cc, 1);
+ break;
+ case FMT_SDPS_PS:
+ gen_movcf_ps(rs, rt, cc, 1);
+ break;
+ default:
+ goto pool32f_invalid;
+ }
+ break;
+ case PREFX:
+ break;
+ default:
+ goto pool32f_invalid;
+ }
+ break;
+#define FINSN_3ARG_SDPS(prfx) \
+ switch ((ctx->opcode >> 8) & 0x3) { \
+ case FMT_SDPS_S: \
+ mips32_op = OPC_##prfx##_S; \
+ goto do_fpop; \
+ case FMT_SDPS_D: \
+ mips32_op = OPC_##prfx##_D; \
+ goto do_fpop; \
+ case FMT_SDPS_PS: \
+ mips32_op = OPC_##prfx##_PS; \
+ goto do_fpop; \
+ default: \
+ goto pool32f_invalid; \
+ }
+ case 0x30:
+ /* regular FP ops */
+ switch ((ctx->opcode >> 6) & 0x3) {
+ case ADD_FMT:
+ FINSN_3ARG_SDPS(ADD);
+ break;
+ case SUB_FMT:
+ FINSN_3ARG_SDPS(SUB);
+ break;
+ case MUL_FMT:
+ FINSN_3ARG_SDPS(MUL);
+ break;
+ case DIV_FMT:
+ fmt = (ctx->opcode >> 8) & 0x3;
+ if (fmt == 1) {
+ mips32_op = OPC_DIV_D;
+ } else if (fmt == 0) {
+ mips32_op = OPC_DIV_S;
+ } else {
+ goto pool32f_invalid;
+ }
+ goto do_fpop;
+ default:
+ goto pool32f_invalid;
+ }
+ break;
+ case 0x38:
+ /* cmovs */
+ switch ((ctx->opcode >> 6) & 0x3) {
+ case MOVN_FMT:
+ FINSN_3ARG_SDPS(MOVN);
+ break;
+ case MOVZ_FMT:
+ FINSN_3ARG_SDPS(MOVZ);
+ break;
+ default:
+ goto pool32f_invalid;
+ }
+ break;
+ do_fpop:
+ gen_farith(ctx, mips32_op, rt, rs, rd, 0);
+ break;
+ default:
+ pool32f_invalid:
+ MIPS_INVAL("pool32f");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ } else {
+ generate_exception_err(ctx, EXCP_CpU, 1);
+ }
+ break;
+ case POOL32I:
+ minor = (ctx->opcode >> 21) & 0x1f;
+ switch (minor) {
+ case BLTZ:
+ mips32_op = OPC_BLTZ;
+ goto do_branch;
+ case BLTZAL:
+ mips32_op = OPC_BLTZAL;
+ goto do_branch;
+ case BLTZALS:
+ mips32_op = OPC_BLTZALS;
+ goto do_branch;
+ case BGEZ:
+ mips32_op = OPC_BGEZ;
+ goto do_branch;
+ case BGEZAL:
+ mips32_op = OPC_BGEZAL;
+ goto do_branch;
+ case BGEZALS:
+ mips32_op = OPC_BGEZALS;
+ goto do_branch;
+ case BLEZ:
+ mips32_op = OPC_BLEZ;
+ goto do_branch;
+ case BGTZ:
+ mips32_op = OPC_BGTZ;
+ do_branch:
+ gen_compute_branch(ctx, mips32_op, 4, rs, -1, imm << 1);
+ *is_branch = 1;
+ break;
+
+ /* Traps */
+ case TLTI:
+ mips32_op = OPC_TLTI;
+ goto do_trapi;
+ case TGEI:
+ mips32_op = OPC_TGEI;
+ goto do_trapi;
+ case TLTIU:
+ mips32_op = OPC_TLTIU;
+ goto do_trapi;
+ case TGEIU:
+ mips32_op = OPC_TGEIU;
+ goto do_trapi;
+ case TNEI:
+ mips32_op = OPC_TNEI;
+ goto do_trapi;
+ case TEQI:
+ mips32_op = OPC_TEQI;
+ do_trapi:
+ gen_trap(ctx, mips32_op, rs, -1, imm);
+ break;
+
+ case BNEZC:
+ case BEQZC:
+ gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ,
+ 4, rs, 0, imm << 1);
+ /* Compact branches don't have a delay slot, so just let
+ the normal delay slot handling take us to the branch
+ target. */
+ break;
+ case LUI:
+ gen_logic_imm(env, OPC_LUI, rs, -1, imm);
+ break;
+ case SYNCI:
+ break;
+ case BC2F:
+ case BC2T:
+ /* COP2: Not implemented. */
+ generate_exception_err(ctx, EXCP_CpU, 2);
+ break;
+ case BC1F:
+ mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1FANY2 : OPC_BC1F;
+ goto do_cp1branch;
+ case BC1T:
+ mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1TANY2 : OPC_BC1T;
+ goto do_cp1branch;
+ case BC1ANY4F:
+ mips32_op = OPC_BC1FANY4;
+ goto do_cp1mips3d;
+ case BC1ANY4T:
+ mips32_op = OPC_BC1TANY4;
+ do_cp1mips3d:
+ check_cop1x(ctx);
+ check_insn(env, ctx, ASE_MIPS3D);
+ /* Fall through */
+ do_cp1branch:
+ gen_compute_branch1(env, ctx, mips32_op,
+ (ctx->opcode >> 18) & 0x7, imm << 1);
+ *is_branch = 1;
+ break;
+ case BPOSGE64:
+ case BPOSGE32:
+ /* MIPS DSP: not implemented */
+ /* Fall through */
+ default:
+ MIPS_INVAL("pool32i");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
+ case POOL32C:
+ minor = (ctx->opcode >> 12) & 0xf;
+ switch (minor) {
+ case LWL:
+ mips32_op = OPC_LWL;
+ goto do_ldst_lr;
+ case SWL:
+ mips32_op = OPC_SWL;
+ goto do_ldst_lr;
+ case LWR:
+ mips32_op = OPC_LWR;
+ goto do_ldst_lr;
+ case SWR:
+ mips32_op = OPC_SWR;
+ goto do_ldst_lr;
+#if defined(TARGET_MIPS64)
+ case LDL:
+ mips32_op = OPC_LDL;
+ goto do_ldst_lr;
+ case SDL:
+ mips32_op = OPC_SDL;
+ goto do_ldst_lr;
+ case LDR:
+ mips32_op = OPC_LDR;
+ goto do_ldst_lr;
+ case SDR:
+ mips32_op = OPC_SDR;
+ goto do_ldst_lr;
+ case LWU:
+ mips32_op = OPC_LWU;
+ goto do_ldst_lr;
+ case LLD:
+ mips32_op = OPC_LLD;
+ goto do_ldst_lr;
+#endif
+ case LL:
+ mips32_op = OPC_LL;
+ do_ldst_lr:
+ gen_ldst(ctx, mips32_op, rt, rs, SIMM(ctx->opcode, 0, 12));
+ break;
+ case SC:
+ gen_st_cond(ctx, OPC_SC, rt, rs, SIMM(ctx->opcode, 0, 12));
+ break;
+#if defined(TARGET_MIPS64)
+ case SCD:
+ gen_st_cond(ctx, OPC_SCD, rt, rs, SIMM(ctx->opcode, 0, 12));
+ break;
+#endif
+ case PREF:
+ /* Treat as no-op */
+ break;
+ default:
+ MIPS_INVAL("pool32c");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ break;
+ case ADDI32:
+ mips32_op = OPC_ADDI;
+ goto do_addi;
+ case ADDIU32:
+ mips32_op = OPC_ADDIU;
+ do_addi:
+ gen_arith_imm(env, ctx, mips32_op, rt, rs, imm);
+ break;
+
+ /* Logical operations */
+ case ORI32:
+ mips32_op = OPC_ORI;
+ goto do_logici;
+ case XORI32:
+ mips32_op = OPC_XORI;
+ goto do_logici;
+ case ANDI32:
+ mips32_op = OPC_ANDI;
+ do_logici:
+ gen_logic_imm(env, mips32_op, rt, rs, imm);
+ break;
+
+ /* Set less than immediate */
+ case SLTI32:
+ mips32_op = OPC_SLTI;
+ goto do_slti;
+ case SLTIU32:
+ mips32_op = OPC_SLTIU;
+ do_slti:
+ gen_slt_imm(env, mips32_op, rt, rs, imm);
+ break;
+ case JALX32:
+ offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
+ gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset);
+ *is_branch = 1;
+ break;
+ case JALS32:
+ offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1;
+ gen_compute_branch(ctx, OPC_JALS, 4, rt, rs, offset);
+ *is_branch = 1;
+ break;
+ case BEQ32:
+ gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1);
+ *is_branch = 1;
+ break;
+ case BNE32:
+ gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1);
+ *is_branch = 1;
+ break;
+ case J32:
+ gen_compute_branch(ctx, OPC_J, 4, rt, rs,
+ (int32_t)(ctx->opcode & 0x3FFFFFF) << 1);
+ *is_branch = 1;
+ break;
+ case JAL32:
+ gen_compute_branch(ctx, OPC_JAL, 4, rt, rs,
+ (int32_t)(ctx->opcode & 0x3FFFFFF) << 1);
+ *is_branch = 1;
+ break;
+ /* Floating point (COP1) */
+ case LWC132:
+ mips32_op = OPC_LWC1;
+ goto do_cop1;
+ case LDC132:
+ mips32_op = OPC_LDC1;
+ goto do_cop1;
+ case SWC132:
+ mips32_op = OPC_SWC1;
+ goto do_cop1;
+ case SDC132:
+ mips32_op = OPC_SDC1;
+ do_cop1:
+ gen_cop1_ldst(env, ctx, mips32_op, rt, rs, imm);
+ break;
+ case ADDIUPC:
+ {
+ int reg = mmreg(ZIMM(ctx->opcode, 23, 3));
+ int offset = SIMM(ctx->opcode, 0, 23) << 2;
+
+ gen_addiupc(ctx, reg, offset, 0, 0);
+ }
+ break;
+ /* Loads and stores */
+ case LB32:
+ mips32_op = OPC_LB;
+ goto do_ldst;
+ case LBU32:
+ mips32_op = OPC_LBU;
+ goto do_ldst;
+ case LH32:
+ mips32_op = OPC_LH;
+ goto do_ldst;
+ case LHU32:
+ mips32_op = OPC_LHU;
+ goto do_ldst;
+ case LW32:
+ mips32_op = OPC_LW;
+ goto do_ldst;
+#ifdef TARGET_MIPS64
+ case LD32:
+ mips32_op = OPC_LD;
+ goto do_ldst;
+ case SD32:
+ mips32_op = OPC_SD;
+ goto do_ldst;
+#endif
+ case SB32:
+ mips32_op = OPC_SB;
+ goto do_ldst;
+ case SH32:
+ mips32_op = OPC_SH;
+ goto do_ldst;
+ case SW32:
+ mips32_op = OPC_SW;
+ do_ldst:
+ gen_ldst(ctx, mips32_op, rt, rs, imm);
+ break;
+ default:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+}
+
+static int decode_micromips_opc (CPUState *env, DisasContext *ctx, int *is_branch)
+{
+ uint32_t op;
+
+ /* make sure instructions are on a halfword boundary */
+ if (ctx->pc & 0x1) {
+ env->CP0_BadVAddr = ctx->pc;
+ generate_exception(ctx, EXCP_AdEL);
+ ctx->bstate = BS_STOP;
+ return 2;
+ }
+
+ op = (ctx->opcode >> 10) & 0x3f;
+ /* Enforce properly-sized instructions in a delay slot */
+ if (ctx->hflags & MIPS_HFLAG_BMASK) {
+ int bits = ctx->hflags & MIPS_HFLAG_BMASK_EXT;
+
+ switch (op) {
+ case POOL32A:
+ case POOL32B:
+ case POOL32I:
+ case POOL32C:
+ case ADDI32:
+ case ADDIU32:
+ case ORI32:
+ case XORI32:
+ case SLTI32:
+ case SLTIU32:
+ case ANDI32:
+ case JALX32:
+ case LBU32:
+ case LHU32:
+ case POOL32F:
+ case JALS32:
+ case BEQ32:
+ case BNE32:
+ case J32:
+ case JAL32:
+ case SB32:
+ case SH32:
+ case POOL32S:
+ case ADDIUPC:
+ case SWC132:
+ case SDC132:
+ case SD32:
+ case SW32:
+ case LB32:
+ case LH32:
+ case DADDIU32:
+ case POOL48A: /* ??? */
+ case LWC132:
+ case LDC132:
+ case LD32:
+ case LW32:
+ if (bits & MIPS_HFLAG_BDS16) {
+ generate_exception(ctx, EXCP_RI);
+ /* Just stop translation; the user is confused. */
+ ctx->bstate = BS_STOP;
+ return 2;
+ }
+ break;
+ case POOL16A:
+ case POOL16B:
+ case POOL16C:
+ case LWGP16:
+ case POOL16F:
+ case LBU16:
+ case LHU16:
+ case LWSP16:
+ case LW16:
+ case SB16:
+ case SH16:
+ case SWSP16:
+ case SW16:
+ case MOVE16:
+ case ANDI16:
+ case POOL16D:
+ case POOL16E:
+ case BEQZ16:
+ case BNEZ16:
+ case B16:
+ case LI16:
+ if (bits & MIPS_HFLAG_BDS32) {
+ generate_exception(ctx, EXCP_RI);
+ /* Just stop translation; the user is confused. */
+ ctx->bstate = BS_STOP;
+ return 2;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ switch (op) {
+ case POOL16A:
+ {
+ int rd = mmreg(uMIPS_RD(ctx->opcode));
+ int rs1 = mmreg(uMIPS_RS1(ctx->opcode));
+ int rs2 = mmreg(uMIPS_RS2(ctx->opcode));
+ uint32_t opc = 0;
+
+ switch (ctx->opcode & 0x1) {
+ case ADDU16:
+ opc = OPC_ADDU;
+ break;
+ case SUBU16:
+ opc = OPC_SUBU;
+ break;
+ }
+
+ gen_arith(env, ctx, opc, rd, rs1, rs2);
+ }
+ break;
+ case POOL16B:
+ {
+ int rd = mmreg(uMIPS_RD(ctx->opcode));
+ int rs = mmreg(uMIPS_RS(ctx->opcode));
+ int amount = (ctx->opcode >> 1) & 0x7;
+ uint32_t opc = 0;
+ amount = amount == 0 ? 8 : amount;
+
+ switch (ctx->opcode & 0x1) {
+ case SLL16:
+ opc = OPC_SLL;
+ break;
+ case SRL16:
+ opc = OPC_SRL;
+ break;
+ }
+
+ gen_shift_imm(env, ctx, opc, rd, rs, amount);
+ }
+ break;
+ case POOL16C:
+ gen_pool16c_insn(env, ctx, is_branch);
+ break;
+ case LWGP16:
+ {
+ int rd = mmreg(uMIPS_RD(ctx->opcode));
+ int rb = 28; /* GP */
+ int16_t offset = SIMM(ctx->opcode, 0, 7) << 2;
+
+ gen_ldst(ctx, OPC_LW, rd, rb, offset);
+ }
+ break;
+ case POOL16F:
+ if (ctx->opcode & 1) {
+ generate_exception(ctx, EXCP_RI);
+ } else {
+ /* MOVEP */
+ int enc_dest = uMIPS_RD(ctx->opcode);
+ int enc_rt = uMIPS_RS2(ctx->opcode);
+ int enc_rs = uMIPS_RS1(ctx->opcode);
+ int rd, rs, re, rt;
+ static const int rd_enc[] = { 5, 5, 6, 4, 4, 4, 4, 4 };
+ static const int re_enc[] = { 6, 7, 7, 21, 22, 5, 6, 7 };
+ static const int rs_rt_enc[] = { 0, 17, 2, 3, 16, 18, 19, 20 };
+
+ rd = rd_enc[enc_dest];
+ re = re_enc[enc_dest];
+ rs = rs_rt_enc[enc_rs];
+ rt = rs_rt_enc[enc_rt];
+
+ gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, 0);
+ gen_arith_imm(env, ctx, OPC_ADDIU, re, rt, 0);
+ }
+ break;
+ case LBU16:
+ {
+ int rd = mmreg(uMIPS_RD(ctx->opcode));
+ int rb = mmreg(uMIPS_RS(ctx->opcode));
+ int16_t offset = ZIMM(ctx->opcode, 0, 4);
+ offset = (offset == 0xf ? -1 : offset);
+
+ gen_ldst(ctx, OPC_LBU, rd, rb, offset);
+ }
+ break;
+ case LHU16:
+ {
+ int rd = mmreg(uMIPS_RD(ctx->opcode));
+ int rb = mmreg(uMIPS_RS(ctx->opcode));
+ int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1;
+
+ gen_ldst(ctx, OPC_LHU, rd, rb, offset);
+ }
+ break;
+ case LWSP16:
+ {
+ int rd = (ctx->opcode >> 5) & 0x1f;
+ int rb = 29; /* SP */
+ int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2;
+
+ gen_ldst(ctx, OPC_LW, rd, rb, offset);
+ }
+ break;
+ case LW16:
+ {
+ int rd = mmreg(uMIPS_RD(ctx->opcode));
+ int rb = mmreg(uMIPS_RS(ctx->opcode));
+ int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2;
+
+ gen_ldst(ctx, OPC_LW, rd, rb, offset);
+ }
+ break;
+ case SB16:
+ {
+ int rd = mmreg2(uMIPS_RD(ctx->opcode));
+ int rb = mmreg(uMIPS_RS(ctx->opcode));
+ int16_t offset = ZIMM(ctx->opcode, 0, 4);
+
+ gen_ldst(ctx, OPC_SB, rd, rb, offset);
+ }
+ break;
+ case SH16:
+ {
+ int rd = mmreg2(uMIPS_RD(ctx->opcode));
+ int rb = mmreg(uMIPS_RS(ctx->opcode));
+ int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1;
+
+ gen_ldst(ctx, OPC_SH, rd, rb, offset);
+ }
+ break;
+ case SWSP16:
+ {
+ int rd = (ctx->opcode >> 5) & 0x1f;
+ int rb = 29; /* SP */
+ int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2;
+
+ gen_ldst(ctx, OPC_SW, rd, rb, offset);
+ }
+ break;
+ case SW16:
+ {
+ int rd = mmreg2(uMIPS_RD(ctx->opcode));
+ int rb = mmreg(uMIPS_RS(ctx->opcode));
+ int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2;
+
+ gen_ldst(ctx, OPC_SW, rd, rb, offset);
+ }
+ break;
+ case MOVE16:
+ {
+ int rd = uMIPS_RD5(ctx->opcode);
+ int rs = uMIPS_RS5(ctx->opcode);
+
+ gen_arith_imm(env, ctx, OPC_ADDIU, rd, rs, 0);
+ }
+ break;
+ case ANDI16:
+ gen_andi16(env, ctx);
+ break;
+ case POOL16D:
+ switch (ctx->opcode & 0x1) {
+ case ADDIUS5:
+ gen_addius5(env, ctx);
+ break;
+ case ADDIUSP:
+ gen_addiusp(env, ctx);
+ break;
+ }
+ break;
+ case POOL16E:
+ switch (ctx->opcode & 0x1) {
+ case ADDIUR2:
+ gen_addiur2(env, ctx);
+ break;
+ case ADDIUR1SP:
+ gen_addiur1sp(env, ctx);
+ break;
+ }
+ break;
+ case B16:
+ gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0,
+ SIMM(ctx->opcode, 0, 10) << 1);
+ *is_branch = 1;
+ break;
+ case BNEZ16:
+ case BEQZ16:
+ gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2,
+ mmreg(uMIPS_RD(ctx->opcode)),
+ 0, SIMM(ctx->opcode, 0, 7) << 1);
+ *is_branch = 1;
+ break;
+ case LI16:
+ {
+ int reg = mmreg(uMIPS_RD(ctx->opcode));
+ int imm = ZIMM(ctx->opcode, 0, 7);
+
+ imm = (imm == 0x7f ? -1 : imm);
+ tcg_gen_movi_tl(cpu_gpr[reg], imm);
+ }
+ break;
+ case RES_20:
+ case RES_28:
+ case RES_29:
+ case RES_30:
+ case RES_31:
+ case RES_38:
+ case RES_39:
+ generate_exception(ctx, EXCP_RI);
+ break;
+ default:
+ decode_micromips32_opc (env, ctx, op, is_branch);
+ return 4;
+ }
+
+ return 2;
+}
+
/* SmartMIPS extension to MIPS32 */
#if defined(TARGET_MIPS64)
@@ -8999,47 +11593,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
gen_bshfl(ctx, op2, rt, rd);
break;
case OPC_RDHWR:
- check_insn(env, ctx, ISA_MIPS32R2);
- {
- TCGv t0 = tcg_temp_new();
-
- switch (rd) {
- case 0:
- save_cpu_state(ctx, 1);
- gen_helper_rdhwr_cpunum(t0);
- gen_store_gpr(t0, rt);
- break;
- case 1:
- save_cpu_state(ctx, 1);
- gen_helper_rdhwr_synci_step(t0);
- gen_store_gpr(t0, rt);
- break;
- case 2:
- save_cpu_state(ctx, 1);
- gen_helper_rdhwr_cc(t0);
- gen_store_gpr(t0, rt);
- break;
- case 3:
- save_cpu_state(ctx, 1);
- gen_helper_rdhwr_ccres(t0);
- gen_store_gpr(t0, rt);
- break;
- case 29:
-#if defined(CONFIG_USER_ONLY)
- tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, tls_value));
- gen_store_gpr(t0, rt);
- break;
-#else
- /* XXX: Some CPUs implement this in hardware.
- Not supported yet. */
-#endif
- default: /* Invalid */
- MIPS_INVAL("rdhwr");
- generate_exception(ctx, EXCP_RI);
- break;
- }
- tcg_temp_free(t0);
- }
+ gen_rdhwr(env, ctx, rt, rd);
break;
case OPC_FORK:
check_insn(env, ctx, ASE_MT);
@@ -9242,12 +11796,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
case OPC_LDC1:
case OPC_SWC1:
case OPC_SDC1:
- if (env->CP0_Config1 & (1 << CP0C1_FP)) {
- check_cp1_enabled(ctx);
- gen_flt_ldst(ctx, op, rt, rs, imm);
- } else {
- generate_exception_err(ctx, EXCP_CpU, 1);
- }
+ gen_cop1_ldst(env, ctx, op, rt, rs, imm);
break;
case OPC_CP1:
@@ -9286,7 +11835,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
case OPC_W_FMT:
case OPC_L_FMT:
case OPC_PS_FMT:
- gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa,
+ gen_farith(ctx, ctx->opcode & FOP(0x3f, 0x1f), rt, rd, sa,
(imm >> 8) & 0x7);
break;
default:
@@ -9375,7 +11924,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
break;
#endif
case OPC_JALX:
- check_insn(env, ctx, ASE_MIPS16);
+ check_insn(env, ctx, ASE_MIPS16 | ASE_MICROMIPS);
offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
gen_compute_branch(ctx, op, 4, rs, rt, offset);
*is_branch = 1;
@@ -9463,11 +12012,15 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
ctx.opcode = ldl_code(ctx.pc);
insn_bytes = 4;
decode_opc(env, &ctx, &is_branch);
+ } else if (env->insn_flags & ASE_MICROMIPS) {
+ ctx.opcode = lduw_code(ctx.pc);
+ insn_bytes = decode_micromips_opc(env, &ctx, &is_branch);
} else if (env->insn_flags & ASE_MIPS16) {
ctx.opcode = lduw_code(ctx.pc);
insn_bytes = decode_mips16_opc(env, &ctx, &is_branch);
} else {
generate_exception(&ctx, EXCP_RI);
+ ctx.bstate = BS_STOP;
break;
}
if (!is_branch) {
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 8d23f47..a3af5b2 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -1746,7 +1746,7 @@ static const TCGTargetOpDef arm_op_defs[] = {
{ -1 },
};
-void tcg_target_init(TCGContext *s)
+static void tcg_target_init(TCGContext *s)
{
#if !defined(CONFIG_USER_ONLY)
/* fail safe */
@@ -1798,7 +1798,7 @@ static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
}
}
-static inline void tcg_out_mov(TCGContext *s, int ret, int arg)
+static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
{
tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ret, 0, arg, SHIFT_IMM_LSL(0));
}
@@ -1809,7 +1809,7 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type,
tcg_out_movi32(s, COND_AL, ret, arg);
}
-void tcg_target_qemu_prologue(TCGContext *s)
+static void tcg_target_qemu_prologue(TCGContext *s)
{
/* There is no need to save r7, it is used to store the address
of the env structure and is not modified by GCC. */
diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c
index 558c21f..7f4653e 100644
--- a/tcg/hppa/tcg-target.c
+++ b/tcg/hppa/tcg-target.c
@@ -338,7 +338,7 @@ static int tcg_target_const_match(tcg_target_long val,
/* supplied by libgcc */
extern void *__canonicalize_funcptr_for_compare(void *);
-static void tcg_out_mov(TCGContext *s, int ret, int arg)
+static void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
{
/* PA1.1 defines COPY as OR r,0,t; PA2.0 defines COPY as LDO 0(r),t
but hppa-dis.c is unaware of this definition */
@@ -498,7 +498,7 @@ static void tcg_out_ori(TCGContext *s, int ret, int arg, tcg_target_ulong m)
}
assert(bs1 == 32 || (1ul << bs1) > m);
- tcg_out_mov(s, ret, arg);
+ tcg_out_mov(s, TCG_TYPE_I32, ret, arg);
tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(-1)
| INSN_SHDEP_CP(31 - bs0) | INSN_DEP_LEN(bs1 - bs0));
}
@@ -528,7 +528,7 @@ static void tcg_out_andi(TCGContext *s, int ret, int arg, tcg_target_ulong m)
if (ls1 == 32) {
tcg_out_extr(s, ret, arg, 0, ls0, 0);
} else {
- tcg_out_mov(s, ret, arg);
+ tcg_out_mov(s, TCG_TYPE_I32, ret, arg);
tcg_out32(s, INSN_DEPI | INSN_R2(ret) | INSN_IM5(0)
| INSN_SHDEP_CP(31 - ls0) | INSN_DEP_LEN(ls1 - ls0));
}
@@ -608,7 +608,7 @@ static void tcg_out_rotr(TCGContext *s, int ret, int arg, int creg)
static void tcg_out_bswap16(TCGContext *s, int ret, int arg, int sign)
{
if (ret != arg) {
- tcg_out_mov(s, ret, arg); /* arg = xxAB */
+ tcg_out_mov(s, TCG_TYPE_I32, ret, arg); /* arg = xxAB */
}
tcg_out_dep(s, ret, ret, 16, 8); /* ret = xBAB */
tcg_out_extr(s, ret, ret, 8, 16, sign); /* ret = ..BA */
@@ -638,7 +638,7 @@ static void tcg_out_call(TCGContext *s, void *func)
tcg_out32(s, INSN_LDIL | INSN_R2(TCG_REG_R20) | reassemble_21(hi));
tcg_out32(s, INSN_BLE_SR4 | INSN_R2(TCG_REG_R20)
| reassemble_17(lo >> 2));
- tcg_out_mov(s, TCG_REG_RP, TCG_REG_R31);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_RP, TCG_REG_R31);
}
}
@@ -685,7 +685,7 @@ static void tcg_out_add2(TCGContext *s, int destl, int desth,
}
tcg_out_arith(s, desth, ah, bh, INSN_ADDC);
- tcg_out_mov(s, destl, tmp);
+ tcg_out_mov(s, TCG_TYPE_I32, destl, tmp);
}
static void tcg_out_sub2(TCGContext *s, int destl, int desth, int al, int ah,
@@ -706,7 +706,7 @@ static void tcg_out_sub2(TCGContext *s, int destl, int desth, int al, int ah,
}
tcg_out_arith(s, desth, ah, bh, INSN_SUBB);
- tcg_out_mov(s, destl, tmp);
+ tcg_out_mov(s, TCG_TYPE_I32, destl, tmp);
}
static void tcg_out_branch(TCGContext *s, int label_index, int nul)
@@ -869,7 +869,7 @@ static void tcg_out_setcond2(TCGContext *s, int cond, TCGArg ret,
break;
}
- tcg_out_mov(s, ret, scratch);
+ tcg_out_mov(s, TCG_TYPE_I32, ret, scratch);
}
#if defined(CONFIG_SOFTMMU)
@@ -1048,9 +1048,9 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
tcg_out_label(s, lab1, (tcg_target_long)s->code_ptr);
argreg = TCG_REG_R26;
- tcg_out_mov(s, argreg--, addrlo_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrlo_reg);
if (TARGET_LONG_BITS == 64) {
- tcg_out_mov(s, argreg--, addrhi_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrhi_reg);
}
tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
@@ -1071,11 +1071,11 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
break;
case 2:
case 2 | 4:
- tcg_out_mov(s, datalo_reg, TCG_REG_RET0);
+ tcg_out_mov(s, TCG_TYPE_I32, datalo_reg, TCG_REG_RET0);
break;
case 3:
- tcg_out_mov(s, datahi_reg, TCG_REG_RET0);
- tcg_out_mov(s, datalo_reg, TCG_REG_RET1);
+ tcg_out_mov(s, TCG_TYPE_I32, datahi_reg, TCG_REG_RET0);
+ tcg_out_mov(s, TCG_TYPE_I32, datalo_reg, TCG_REG_RET1);
break;
default:
tcg_abort();
@@ -1167,9 +1167,9 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
tcg_out_label(s, lab1, (tcg_target_long)s->code_ptr);
argreg = TCG_REG_R26;
- tcg_out_mov(s, argreg--, addrlo_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrlo_reg);
if (TARGET_LONG_BITS == 64) {
- tcg_out_mov(s, argreg--, addrhi_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrhi_reg);
}
switch(opc) {
@@ -1182,7 +1182,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
break;
case 2:
- tcg_out_mov(s, argreg--, datalo_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, argreg--, datalo_reg);
tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
break;
case 3:
@@ -1196,8 +1196,8 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
argreg = TCG_REG_R20;
tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index);
}
- tcg_out_mov(s, TCG_REG_R23, datahi_reg);
- tcg_out_mov(s, TCG_REG_R24, datalo_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R23, datahi_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R24, datalo_reg);
tcg_out_st(s, TCG_TYPE_I32, argreg, TCG_REG_SP,
TCG_TARGET_CALL_STACK_OFFSET - 4);
break;
@@ -1600,7 +1600,7 @@ static int tcg_target_callee_save_regs[] = {
TCG_REG_R18
};
-void tcg_target_qemu_prologue(TCGContext *s)
+static void tcg_target_qemu_prologue(TCGContext *s)
{
int frame_size, i;
@@ -1637,7 +1637,7 @@ void tcg_target_qemu_prologue(TCGContext *s)
/* Jump to TB, and adjust R18 to be the return address. */
tcg_out32(s, INSN_BLE_SR4 | INSN_R2(TCG_REG_R26));
- tcg_out_mov(s, TCG_REG_R18, TCG_REG_R31);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R18, TCG_REG_R31);
/* Restore callee saved registers. */
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_RP, TCG_REG_SP, -frame_size - 20);
@@ -1652,7 +1652,7 @@ void tcg_target_qemu_prologue(TCGContext *s)
TCG_REG_SP, -frame_size, INSN_LDWM);
}
-void tcg_target_init(TCGContext *s)
+static void tcg_target_init(TCGContext *s)
{
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c
index 3600c35..bb19a95 100644
--- a/tcg/i386/tcg-target.c
+++ b/tcg/i386/tcg-target.c
@@ -24,18 +24,33 @@
#ifndef NDEBUG
static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
- "%eax",
- "%ecx",
- "%edx",
- "%ebx",
- "%esp",
- "%ebp",
- "%esi",
- "%edi",
+#if TCG_TARGET_REG_BITS == 64
+ "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
+ "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+#else
+ "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
+#endif
};
#endif
static const int tcg_target_reg_alloc_order[] = {
+#if TCG_TARGET_REG_BITS == 64
+ TCG_REG_RBP,
+ TCG_REG_RBX,
+ TCG_REG_R12,
+ TCG_REG_R13,
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_R10,
+ TCG_REG_R11,
+ TCG_REG_R9,
+ TCG_REG_R8,
+ TCG_REG_RCX,
+ TCG_REG_RDX,
+ TCG_REG_RSI,
+ TCG_REG_RDI,
+ TCG_REG_RAX,
+#else
TCG_REG_EBX,
TCG_REG_ESI,
TCG_REG_EDI,
@@ -43,10 +58,28 @@ static const int tcg_target_reg_alloc_order[] = {
TCG_REG_ECX,
TCG_REG_EDX,
TCG_REG_EAX,
+#endif
};
-static const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, TCG_REG_ECX };
-static const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX };
+static const int tcg_target_call_iarg_regs[] = {
+#if TCG_TARGET_REG_BITS == 64
+ TCG_REG_RDI,
+ TCG_REG_RSI,
+ TCG_REG_RDX,
+ TCG_REG_RCX,
+ TCG_REG_R8,
+ TCG_REG_R9,
+#else
+ TCG_REG_EAX,
+ TCG_REG_EDX,
+ TCG_REG_ECX
+#endif
+};
+
+static const int tcg_target_call_oarg_regs[2] = {
+ TCG_REG_EAX,
+ TCG_REG_EDX
+};
static uint8_t *tb_ret_addr;
@@ -55,14 +88,15 @@ static void patch_reloc(uint8_t *code_ptr, int type,
{
value += addend;
switch(type) {
- case R_386_32:
- *(uint32_t *)code_ptr = value;
- break;
case R_386_PC32:
- *(uint32_t *)code_ptr = value - (long)code_ptr;
+ value -= (uintptr_t)code_ptr;
+ if (value != (int32_t)value) {
+ tcg_abort();
+ }
+ *(uint32_t *)code_ptr = value;
break;
case R_386_PC8:
- value -= (long)code_ptr;
+ value -= (uintptr_t)code_ptr;
if (value != (int8_t)value) {
tcg_abort();
}
@@ -76,6 +110,10 @@ static void patch_reloc(uint8_t *code_ptr, int type,
/* maximum number of register used for input function arguments */
static inline int tcg_target_get_call_iarg_regs_count(int flags)
{
+ if (TCG_TARGET_REG_BITS == 64) {
+ return 6;
+ }
+
flags &= TCG_CALL_TYPE_MASK;
switch(flags) {
case TCG_CALL_TYPE_STD:
@@ -122,20 +160,42 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
break;
case 'q':
ct->ct |= TCG_CT_REG;
- tcg_regset_set32(ct->u.regs, 0, 0xf);
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_regset_set32(ct->u.regs, 0, 0xffff);
+ } else {
+ tcg_regset_set32(ct->u.regs, 0, 0xf);
+ }
break;
case 'r':
ct->ct |= TCG_CT_REG;
- tcg_regset_set32(ct->u.regs, 0, 0xff);
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_regset_set32(ct->u.regs, 0, 0xffff);
+ } else {
+ tcg_regset_set32(ct->u.regs, 0, 0xff);
+ }
break;
/* qemu_ld/st address constraint */
case 'L':
ct->ct |= TCG_CT_REG;
- tcg_regset_set32(ct->u.regs, 0, 0xff);
- tcg_regset_reset_reg(ct->u.regs, TCG_REG_EAX);
- tcg_regset_reset_reg(ct->u.regs, TCG_REG_EDX);
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_regset_set32(ct->u.regs, 0, 0xffff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_RSI);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDI);
+ } else {
+ tcg_regset_set32(ct->u.regs, 0, 0xff);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_EAX);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_EDX);
+ }
+ break;
+
+ case 'e':
+ ct->ct |= TCG_CT_CONST_S32;
+ break;
+ case 'Z':
+ ct->ct |= TCG_CT_CONST_U32;
break;
+
default:
return -1;
}
@@ -148,16 +208,38 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
static inline int tcg_target_const_match(tcg_target_long val,
const TCGArgConstraint *arg_ct)
{
- int ct;
- ct = arg_ct->ct;
- if (ct & TCG_CT_CONST)
+ int ct = arg_ct->ct;
+ if (ct & TCG_CT_CONST) {
return 1;
- else
- return 0;
+ }
+ if ((ct & TCG_CT_CONST_S32) && val == (int32_t)val) {
+ return 1;
+ }
+ if ((ct & TCG_CT_CONST_U32) && val == (uint32_t)val) {
+ return 1;
+ }
+ return 0;
}
+#if TCG_TARGET_REG_BITS == 64
+# define LOWREGMASK(x) ((x) & 7)
+#else
+# define LOWREGMASK(x) (x)
+#endif
+
#define P_EXT 0x100 /* 0x0f opcode prefix */
#define P_DATA16 0x200 /* 0x66 opcode prefix */
+#if TCG_TARGET_REG_BITS == 64
+# define P_ADDR32 0x400 /* 0x67 opcode prefix */
+# define P_REXW 0x800 /* Set REX.W = 1 */
+# define P_REXB_R 0x1000 /* REG field as byte register */
+# define P_REXB_RM 0x2000 /* R/M field as byte register */
+#else
+# define P_ADDR32 0
+# define P_REXW 0
+# define P_REXB_R 0
+# define P_REXB_RM 0
+#endif
#define OPC_ARITH_EvIz (0x81)
#define OPC_ARITH_EvIb (0x83)
@@ -179,9 +261,11 @@ static inline int tcg_target_const_match(tcg_target_long val,
#define OPC_MOVB_EvGv (0x88) /* stores, more or less */
#define OPC_MOVL_EvGv (0x89) /* stores, more or less */
#define OPC_MOVL_GvEv (0x8b) /* loads, more or less */
+#define OPC_MOVL_EvIz (0xc7)
#define OPC_MOVL_Iv (0xb8)
#define OPC_MOVSBL (0xbe | P_EXT)
#define OPC_MOVSWL (0xbf | P_EXT)
+#define OPC_MOVSLQ (0x63 | P_REXW)
#define OPC_MOVZBL (0xb6 | P_EXT)
#define OPC_MOVZWL (0xb7 | P_EXT)
#define OPC_POP_r32 (0x58)
@@ -189,7 +273,7 @@ static inline int tcg_target_const_match(tcg_target_long val,
#define OPC_PUSH_Iv (0x68)
#define OPC_PUSH_Ib (0x6a)
#define OPC_RET (0xc3)
-#define OPC_SETCC (0x90 | P_EXT) /* ... plus condition code */
+#define OPC_SETCC (0x90 | P_EXT | P_REXB_RM) /* ... plus cc */
#define OPC_SHIFT_1 (0xd1)
#define OPC_SHIFT_Ib (0xc1)
#define OPC_SHIFT_cl (0xd3)
@@ -226,6 +310,8 @@ static inline int tcg_target_const_match(tcg_target_long val,
#define EXT3_IDIV 7
/* Group 5 opcode extensions for 0xff. To be used with OPC_GRP5. */
+#define EXT5_INC_Ev 0
+#define EXT5_DEC_Ev 1
#define EXT5_CALLN_Ev 2
#define EXT5_JMPN_Ev 4
@@ -261,7 +347,45 @@ static const uint8_t tcg_cond_to_jcc[10] = {
[TCG_COND_GTU] = JCC_JA,
};
-static inline void tcg_out_opc(TCGContext *s, int opc)
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_opc(TCGContext *s, int opc, int r, int rm, int x)
+{
+ int rex;
+
+ if (opc & P_DATA16) {
+ /* We should never be asking for both 16 and 64-bit operation. */
+ assert((opc & P_REXW) == 0);
+ tcg_out8(s, 0x66);
+ }
+ if (opc & P_ADDR32) {
+ tcg_out8(s, 0x67);
+ }
+
+ rex = 0;
+ rex |= (opc & P_REXW) >> 8; /* REX.W */
+ rex |= (r & 8) >> 1; /* REX.R */
+ rex |= (x & 8) >> 2; /* REX.X */
+ rex |= (rm & 8) >> 3; /* REX.B */
+
+ /* P_REXB_{R,RM} indicates that the given register is the low byte.
+ For %[abcd]l we need no REX prefix, but for %{si,di,bp,sp}l we do,
+ as otherwise the encoding indicates %[abcd]h. Note that the values
+ that are ORed in merely indicate that the REX byte must be present;
+ those bits get discarded in output. */
+ rex |= opc & (r >= 4 ? P_REXB_R : 0);
+ rex |= opc & (rm >= 4 ? P_REXB_RM : 0);
+
+ if (rex) {
+ tcg_out8(s, (uint8_t)(rex | 0x40));
+ }
+
+ if (opc & P_EXT) {
+ tcg_out8(s, 0x0f);
+ }
+ tcg_out8(s, opc);
+}
+#else
+static void tcg_out_opc(TCGContext *s, int opc)
{
if (opc & P_DATA16) {
tcg_out8(s, 0x66);
@@ -271,36 +395,69 @@ static inline void tcg_out_opc(TCGContext *s, int opc)
}
tcg_out8(s, opc);
}
+/* Discard the register arguments to tcg_out_opc early, so as not to penalize
+ the 32-bit compilation paths. This method works with all versions of gcc,
+ whereas relying on optimization may not be able to exclude them. */
+#define tcg_out_opc(s, opc, r, rm, x) (tcg_out_opc)(s, opc)
+#endif
-static inline void tcg_out_modrm(TCGContext *s, int opc, int r, int rm)
+static void tcg_out_modrm(TCGContext *s, int opc, int r, int rm)
{
- tcg_out_opc(s, opc);
- tcg_out8(s, 0xc0 | (r << 3) | rm);
+ tcg_out_opc(s, opc, r, rm, 0);
+ tcg_out8(s, 0xc0 | (LOWREGMASK(r) << 3) | LOWREGMASK(rm));
}
/* Output an opcode with a full "rm + (index<<shift) + offset" address mode.
- We handle either RM and INDEX missing with a -1 value. */
+ We handle either RM and INDEX missing with a negative value. In 64-bit
+ mode for absolute addresses, ~RM is the size of the immediate operand
+ that will follow the instruction. */
static void tcg_out_modrm_sib_offset(TCGContext *s, int opc, int r, int rm,
- int index, int shift, int32_t offset)
+ int index, int shift,
+ tcg_target_long offset)
{
int mod, len;
- if (index == -1 && rm == -1) {
- /* Absolute address. */
- tcg_out_opc(s, opc);
- tcg_out8(s, (r << 3) | 5);
- tcg_out32(s, offset);
- return;
- }
+ if (index < 0 && rm < 0) {
+ if (TCG_TARGET_REG_BITS == 64) {
+ /* Try for a rip-relative addressing mode. This has replaced
+ the 32-bit-mode absolute addressing encoding. */
+ tcg_target_long pc = (tcg_target_long)s->code_ptr + 5 + ~rm;
+ tcg_target_long disp = offset - pc;
+ if (disp == (int32_t)disp) {
+ tcg_out_opc(s, opc, r, 0, 0);
+ tcg_out8(s, (LOWREGMASK(r) << 3) | 5);
+ tcg_out32(s, disp);
+ return;
+ }
- tcg_out_opc(s, opc);
+ /* Try for an absolute address encoding. This requires the
+ use of the MODRM+SIB encoding and is therefore larger than
+ rip-relative addressing. */
+ if (offset == (int32_t)offset) {
+ tcg_out_opc(s, opc, r, 0, 0);
+ tcg_out8(s, (LOWREGMASK(r) << 3) | 4);
+ tcg_out8(s, (4 << 3) | 5);
+ tcg_out32(s, offset);
+ return;
+ }
+
+ /* ??? The memory isn't directly addressable. */
+ tcg_abort();
+ } else {
+ /* Absolute address. */
+ tcg_out_opc(s, opc, r, 0, 0);
+ tcg_out8(s, (r << 3) | 5);
+ tcg_out32(s, offset);
+ return;
+ }
+ }
/* Find the length of the immediate addend. Note that the encoding
that would be used for (%ebp) indicates absolute addressing. */
- if (rm == -1) {
+ if (rm < 0) {
mod = 0, len = 4, rm = 5;
- } else if (offset == 0 && rm != TCG_REG_EBP) {
+ } else if (offset == 0 && LOWREGMASK(rm) != TCG_REG_EBP) {
mod = 0, len = 0;
} else if (offset == (int8_t)offset) {
mod = 0x40, len = 1;
@@ -310,22 +467,25 @@ static void tcg_out_modrm_sib_offset(TCGContext *s, int opc, int r, int rm,
/* Use a single byte MODRM format if possible. Note that the encoding
that would be used for %esp is the escape to the two byte form. */
- if (index == -1 && rm != TCG_REG_ESP) {
+ if (index < 0 && LOWREGMASK(rm) != TCG_REG_ESP) {
/* Single byte MODRM format. */
- tcg_out8(s, mod | (r << 3) | rm);
+ tcg_out_opc(s, opc, r, rm, 0);
+ tcg_out8(s, mod | (LOWREGMASK(r) << 3) | LOWREGMASK(rm));
} else {
/* Two byte MODRM+SIB format. */
/* Note that the encoding that would place %esp into the index
- field indicates no index register. */
- if (index == -1) {
+ field indicates no index register. In 64-bit mode, the REX.X
+ bit counts, so %r12 can be used as the index. */
+ if (index < 0) {
index = 4;
} else {
assert(index != TCG_REG_ESP);
}
- tcg_out8(s, mod | (r << 3) | 4);
- tcg_out8(s, (shift << 6) | (index << 3) | rm);
+ tcg_out_opc(s, opc, r, rm, index);
+ tcg_out8(s, mod | (LOWREGMASK(r) << 3) | 4);
+ tcg_out8(s, (shift << 6) | (LOWREGMASK(index) << 3) | LOWREGMASK(rm));
}
if (len == 1) {
@@ -335,9 +495,9 @@ static void tcg_out_modrm_sib_offset(TCGContext *s, int opc, int r, int rm,
}
}
-/* rm == -1 means no register index */
-static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r, int rm,
- int32_t offset)
+/* A simplification of the above with no index or shift. */
+static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r,
+ int rm, tcg_target_long offset)
{
tcg_out_modrm_sib_offset(s, opc, r, rm, -1, 0, offset);
}
@@ -345,58 +505,75 @@ static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r, int rm,
/* Generate dest op= src. Uses the same ARITH_* codes as tgen_arithi. */
static inline void tgen_arithr(TCGContext *s, int subop, int dest, int src)
{
- tcg_out_modrm(s, OPC_ARITH_GvEv + (subop << 3), dest, src);
+ /* Propagate an opcode prefix, such as P_REXW. */
+ int ext = subop & ~0x7;
+ subop &= 0x7;
+
+ tcg_out_modrm(s, OPC_ARITH_GvEv + (subop << 3) + ext, dest, src);
}
-static inline void tcg_out_mov(TCGContext *s, int ret, int arg)
+static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
{
if (arg != ret) {
- tcg_out_modrm(s, OPC_MOVL_GvEv, ret, arg);
+ int opc = OPC_MOVL_GvEv + (type == TCG_TYPE_I64 ? P_REXW : 0);
+ tcg_out_modrm(s, opc, ret, arg);
}
}
-static inline void tcg_out_movi(TCGContext *s, TCGType type,
- int ret, int32_t arg)
+static void tcg_out_movi(TCGContext *s, TCGType type,
+ int ret, tcg_target_long arg)
{
if (arg == 0) {
tgen_arithr(s, ARITH_XOR, ret, ret);
+ return;
+ } else if (arg == (uint32_t)arg || type == TCG_TYPE_I32) {
+ tcg_out_opc(s, OPC_MOVL_Iv + LOWREGMASK(ret), 0, ret, 0);
+ tcg_out32(s, arg);
+ } else if (arg == (int32_t)arg) {
+ tcg_out_modrm(s, OPC_MOVL_EvIz + P_REXW, 0, ret);
+ tcg_out32(s, arg);
} else {
- tcg_out8(s, OPC_MOVL_Iv + ret);
+ tcg_out_opc(s, OPC_MOVL_Iv + P_REXW + LOWREGMASK(ret), 0, ret, 0);
tcg_out32(s, arg);
+ tcg_out32(s, arg >> 31 >> 1);
}
}
static inline void tcg_out_pushi(TCGContext *s, tcg_target_long val)
{
if (val == (int8_t)val) {
- tcg_out_opc(s, OPC_PUSH_Ib);
+ tcg_out_opc(s, OPC_PUSH_Ib, 0, 0, 0);
tcg_out8(s, val);
- } else {
- tcg_out_opc(s, OPC_PUSH_Iv);
+ } else if (val == (int32_t)val) {
+ tcg_out_opc(s, OPC_PUSH_Iv, 0, 0, 0);
tcg_out32(s, val);
+ } else {
+ tcg_abort();
}
}
static inline void tcg_out_push(TCGContext *s, int reg)
{
- tcg_out_opc(s, OPC_PUSH_r32 + reg);
+ tcg_out_opc(s, OPC_PUSH_r32 + LOWREGMASK(reg), 0, reg, 0);
}
static inline void tcg_out_pop(TCGContext *s, int reg)
{
- tcg_out_opc(s, OPC_POP_r32 + reg);
+ tcg_out_opc(s, OPC_POP_r32 + LOWREGMASK(reg), 0, reg, 0);
}
static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
int arg1, tcg_target_long arg2)
{
- tcg_out_modrm_offset(s, OPC_MOVL_GvEv, ret, arg1, arg2);
+ int opc = OPC_MOVL_GvEv + (type == TCG_TYPE_I64 ? P_REXW : 0);
+ tcg_out_modrm_offset(s, opc, ret, arg1, arg2);
}
static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
int arg1, tcg_target_long arg2)
{
- tcg_out_modrm_offset(s, OPC_MOVL_EvGv, arg, arg1, arg2);
+ int opc = OPC_MOVL_EvGv + (type == TCG_TYPE_I64 ? P_REXW : 0);
+ tcg_out_modrm_offset(s, opc, arg, arg1, arg2);
}
static void tcg_out_shifti(TCGContext *s, int subopc, int reg, int count)
@@ -406,35 +583,35 @@ static void tcg_out_shifti(TCGContext *s, int subopc, int reg, int count)
subopc &= 0x7;
if (count == 1) {
- tcg_out_modrm(s, OPC_SHIFT_1 | ext, subopc, reg);
+ tcg_out_modrm(s, OPC_SHIFT_1 + ext, subopc, reg);
} else {
- tcg_out_modrm(s, OPC_SHIFT_Ib | ext, subopc, reg);
+ tcg_out_modrm(s, OPC_SHIFT_Ib + ext, subopc, reg);
tcg_out8(s, count);
}
}
static inline void tcg_out_bswap32(TCGContext *s, int reg)
{
- tcg_out_opc(s, OPC_BSWAP + reg);
+ tcg_out_opc(s, OPC_BSWAP + LOWREGMASK(reg), 0, reg, 0);
}
static inline void tcg_out_rolw_8(TCGContext *s, int reg)
{
- tcg_out_shifti(s, SHIFT_ROL | P_DATA16, reg, 8);
+ tcg_out_shifti(s, SHIFT_ROL + P_DATA16, reg, 8);
}
static inline void tcg_out_ext8u(TCGContext *s, int dest, int src)
{
/* movzbl */
- assert(src < 4);
- tcg_out_modrm(s, OPC_MOVZBL, dest, src);
+ assert(src < 4 || TCG_TARGET_REG_BITS == 64);
+ tcg_out_modrm(s, OPC_MOVZBL + P_REXB_RM, dest, src);
}
-static void tcg_out_ext8s(TCGContext *s, int dest, int src)
+static void tcg_out_ext8s(TCGContext *s, int dest, int src, int rexw)
{
/* movsbl */
- assert(src < 4);
- tcg_out_modrm(s, OPC_MOVSBL, dest, src);
+ assert(src < 4 || TCG_TARGET_REG_BITS == 64);
+ tcg_out_modrm(s, OPC_MOVSBL + P_REXB_RM + rexw, dest, src);
}
static inline void tcg_out_ext16u(TCGContext *s, int dest, int src)
@@ -443,38 +620,94 @@ static inline void tcg_out_ext16u(TCGContext *s, int dest, int src)
tcg_out_modrm(s, OPC_MOVZWL, dest, src);
}
-static inline void tcg_out_ext16s(TCGContext *s, int dest, int src)
+static inline void tcg_out_ext16s(TCGContext *s, int dest, int src, int rexw)
{
- /* movswl */
- tcg_out_modrm(s, OPC_MOVSWL, dest, src);
+ /* movsw[lq] */
+ tcg_out_modrm(s, OPC_MOVSWL + rexw, dest, src);
}
-static inline void tgen_arithi(TCGContext *s, int c, int r0,
- int32_t val, int cf)
+static inline void tcg_out_ext32u(TCGContext *s, int dest, int src)
{
+ /* 32-bit mov zero extends. */
+ tcg_out_modrm(s, OPC_MOVL_GvEv, dest, src);
+}
+
+static inline void tcg_out_ext32s(TCGContext *s, int dest, int src)
+{
+ tcg_out_modrm(s, OPC_MOVSLQ, dest, src);
+}
+
+static inline void tcg_out_bswap64(TCGContext *s, int reg)
+{
+ tcg_out_opc(s, OPC_BSWAP + P_REXW + LOWREGMASK(reg), 0, reg, 0);
+}
+
+static void tgen_arithi(TCGContext *s, int c, int r0,
+ tcg_target_long val, int cf)
+{
+ int rexw = 0;
+
+ if (TCG_TARGET_REG_BITS == 64) {
+ rexw = c & -8;
+ c &= 7;
+ }
+
/* ??? While INC is 2 bytes shorter than ADDL $1, they also induce
partial flags update stalls on Pentium4 and are not recommended
by current Intel optimization manuals. */
if (!cf && (c == ARITH_ADD || c == ARITH_SUB) && (val == 1 || val == -1)) {
- int opc = ((c == ARITH_ADD) ^ (val < 0) ? OPC_INC_r32 : OPC_DEC_r32);
- tcg_out_opc(s, opc + r0);
- } else if (val == (int8_t)val) {
- tcg_out_modrm(s, OPC_ARITH_EvIb, c, r0);
+ int is_inc = (c == ARITH_ADD) ^ (val < 0);
+ if (TCG_TARGET_REG_BITS == 64) {
+ /* The single-byte increment encodings are re-tasked as the
+ REX prefixes. Use the MODRM encoding. */
+ tcg_out_modrm(s, OPC_GRP5 + rexw,
+ (is_inc ? EXT5_INC_Ev : EXT5_DEC_Ev), r0);
+ } else {
+ tcg_out8(s, (is_inc ? OPC_INC_r32 : OPC_DEC_r32) + r0);
+ }
+ return;
+ }
+
+ if (c == ARITH_AND) {
+ if (TCG_TARGET_REG_BITS == 64) {
+ if (val == 0xffffffffu) {
+ tcg_out_ext32u(s, r0, r0);
+ return;
+ }
+ if (val == (uint32_t)val) {
+ /* AND with no high bits set can use a 32-bit operation. */
+ rexw = 0;
+ }
+ }
+ if (val == 0xffu && (r0 < 4 || TCG_TARGET_REG_BITS == 64)) {
+ tcg_out_ext8u(s, r0, r0);
+ return;
+ }
+ if (val == 0xffffu) {
+ tcg_out_ext16u(s, r0, r0);
+ return;
+ }
+ }
+
+ if (val == (int8_t)val) {
+ tcg_out_modrm(s, OPC_ARITH_EvIb + rexw, c, r0);
tcg_out8(s, val);
- } else if (c == ARITH_AND && val == 0xffu && r0 < 4) {
- tcg_out_ext8u(s, r0, r0);
- } else if (c == ARITH_AND && val == 0xffffu) {
- tcg_out_ext16u(s, r0, r0);
- } else {
- tcg_out_modrm(s, OPC_ARITH_EvIz, c, r0);
+ return;
+ }
+ if (rexw == 0 || val == (int32_t)val) {
+ tcg_out_modrm(s, OPC_ARITH_EvIz + rexw, c, r0);
tcg_out32(s, val);
+ return;
}
+
+ tcg_abort();
}
static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
{
- if (val != 0)
- tgen_arithi(s, ARITH_ADD, reg, val, 0);
+ if (val != 0) {
+ tgen_arithi(s, ARITH_ADD + P_REXW, reg, val, 0);
+ }
}
/* Use SMALL != 0 to force a short forward branch. */
@@ -501,7 +734,7 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index, int small)
tcg_out8(s, OPC_JMP_long);
tcg_out32(s, val - 5);
} else {
- tcg_out_opc(s, OPC_JCC_long + opc);
+ tcg_out_opc(s, OPC_JCC_long + opc, 0, 0, 0);
tcg_out32(s, val - 6);
}
}
@@ -517,7 +750,7 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index, int small)
if (opc == -1) {
tcg_out8(s, OPC_JMP_long);
} else {
- tcg_out_opc(s, OPC_JCC_long + opc);
+ tcg_out_opc(s, OPC_JCC_long + opc, 0, 0, 0);
}
tcg_out_reloc(s, s->code_ptr, R_386_PC32, label_index, -4);
s->code_ptr += 4;
@@ -525,28 +758,37 @@ static void tcg_out_jxx(TCGContext *s, int opc, int label_index, int small)
}
static void tcg_out_cmp(TCGContext *s, TCGArg arg1, TCGArg arg2,
- int const_arg2)
+ int const_arg2, int rexw)
{
if (const_arg2) {
if (arg2 == 0) {
/* test r, r */
- tcg_out_modrm(s, OPC_TESTL, arg1, arg1);
+ tcg_out_modrm(s, OPC_TESTL + rexw, arg1, arg1);
} else {
- tgen_arithi(s, ARITH_CMP, arg1, arg2, 0);
+ tgen_arithi(s, ARITH_CMP + rexw, arg1, arg2, 0);
}
} else {
- tgen_arithr(s, ARITH_CMP, arg1, arg2);
+ tgen_arithr(s, ARITH_CMP + rexw, arg1, arg2);
}
}
-static void tcg_out_brcond(TCGContext *s, TCGCond cond,
- TCGArg arg1, TCGArg arg2, int const_arg2,
- int label_index, int small)
+static void tcg_out_brcond32(TCGContext *s, TCGCond cond,
+ TCGArg arg1, TCGArg arg2, int const_arg2,
+ int label_index, int small)
{
- tcg_out_cmp(s, arg1, arg2, const_arg2);
+ tcg_out_cmp(s, arg1, arg2, const_arg2, 0);
tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index, small);
}
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_brcond64(TCGContext *s, TCGCond cond,
+ TCGArg arg1, TCGArg arg2, int const_arg2,
+ int label_index, int small)
+{
+ tcg_out_cmp(s, arg1, arg2, const_arg2, P_REXW);
+ tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index, small);
+}
+#else
/* XXX: we implement it at the target level to avoid having to
handle cross basic blocks temporaries */
static void tcg_out_brcond2(TCGContext *s, const TCGArg *args,
@@ -556,87 +798,97 @@ static void tcg_out_brcond2(TCGContext *s, const TCGArg *args,
label_next = gen_new_label();
switch(args[4]) {
case TCG_COND_EQ:
- tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2],
- label_next, 1);
- tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_NE, args[0], args[2], const_args[2],
+ label_next, 1);
+ tcg_out_brcond32(s, TCG_COND_EQ, args[1], args[3], const_args[3],
+ args[5], small);
break;
case TCG_COND_NE:
- tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2],
- args[5], small);
- tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_NE, args[0], args[2], const_args[2],
+ args[5], small);
+ tcg_out_brcond32(s, TCG_COND_NE, args[1], args[3], const_args[3],
+ args[5], small);
break;
case TCG_COND_LT:
- tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_LT, args[1], args[3], const_args[3],
+ args[5], small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_LTU, args[0], args[2], const_args[2],
+ args[5], small);
break;
case TCG_COND_LE:
- tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_LT, args[1], args[3], const_args[3],
+ args[5], small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_LEU, args[0], args[2], const_args[2],
+ args[5], small);
break;
case TCG_COND_GT:
- tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_GT, args[1], args[3], const_args[3],
+ args[5], small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_GTU, args[0], args[2], const_args[2],
+ args[5], small);
break;
case TCG_COND_GE:
- tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_GT, args[1], args[3], const_args[3],
+ args[5], small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_GEU, args[0], args[2], const_args[2],
+ args[5], small);
break;
case TCG_COND_LTU:
- tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_LTU, args[1], args[3], const_args[3],
+ args[5], small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_LTU, args[0], args[2], const_args[2],
+ args[5], small);
break;
case TCG_COND_LEU:
- tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_LTU, args[1], args[3], const_args[3],
+ args[5], small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_LEU, args[0], args[2], const_args[2],
+ args[5], small);
break;
case TCG_COND_GTU:
- tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_GTU, args[1], args[3], const_args[3],
+ args[5], small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_GTU, args[0], args[2], const_args[2],
+ args[5], small);
break;
case TCG_COND_GEU:
- tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_GTU, args[1], args[3], const_args[3],
+ args[5], small);
tcg_out_jxx(s, JCC_JNE, label_next, 1);
- tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2],
- args[5], small);
+ tcg_out_brcond32(s, TCG_COND_GEU, args[0], args[2], const_args[2],
+ args[5], small);
break;
default:
tcg_abort();
}
tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr);
}
+#endif
-static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGArg dest,
- TCGArg arg1, TCGArg arg2, int const_arg2)
+static void tcg_out_setcond32(TCGContext *s, TCGCond cond, TCGArg dest,
+ TCGArg arg1, TCGArg arg2, int const_arg2)
{
- tcg_out_cmp(s, arg1, arg2, const_arg2);
+ tcg_out_cmp(s, arg1, arg2, const_arg2, 0);
tcg_out_modrm(s, OPC_SETCC | tcg_cond_to_jcc[cond], 0, dest);
tcg_out_ext8u(s, dest, dest);
}
+#if TCG_TARGET_REG_BITS == 64
+static void tcg_out_setcond64(TCGContext *s, TCGCond cond, TCGArg dest,
+ TCGArg arg1, TCGArg arg2, int const_arg2)
+{
+ tcg_out_cmp(s, arg1, arg2, const_arg2, P_REXW);
+ tcg_out_modrm(s, OPC_SETCC | tcg_cond_to_jcc[cond], 0, dest);
+ tcg_out_ext8u(s, dest, dest);
+}
+#else
static void tcg_out_setcond2(TCGContext *s, const TCGArg *args,
const int *const_args)
{
@@ -678,11 +930,30 @@ static void tcg_out_setcond2(TCGContext *s, const TCGArg *args,
tcg_out_label(s, label_over, (tcg_target_long)s->code_ptr);
}
}
+#endif
+
+static void tcg_out_branch(TCGContext *s, int call, tcg_target_long dest)
+{
+ tcg_target_long disp = dest - (tcg_target_long)s->code_ptr - 5;
+
+ if (disp == (int32_t)disp) {
+ tcg_out_opc(s, call ? OPC_CALL_Jz : OPC_JMP_long, 0, 0, 0);
+ tcg_out32(s, disp);
+ } else {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R10, dest);
+ tcg_out_modrm(s, OPC_GRP5,
+ call ? EXT5_CALLN_Ev : EXT5_JMPN_Ev, TCG_REG_R10);
+ }
+}
+
+static inline void tcg_out_calli(TCGContext *s, tcg_target_long dest)
+{
+ tcg_out_branch(s, 1, dest);
+}
-static void tcg_out_calli(TCGContext *s, tcg_target_long dest)
+static void tcg_out_jmp(TCGContext *s, tcg_target_long dest)
{
- tcg_out_opc(s, OPC_CALL_Jz);
- tcg_out32(s, dest - (tcg_target_long)s->code_ptr - 4);
+ tcg_out_branch(s, 0, dest);
}
#if defined(CONFIG_SOFTMMU)
@@ -718,11 +989,12 @@ static void *qemu_st_helpers[4] = {
LABEL_PTRS is filled with 1 (32-bit addresses) or 2 (64-bit addresses)
positions of the displacements of forward jumps to the TLB miss case.
- EAX is loaded with the low part of the address. In the TLB hit case,
- it has been adjusted as indicated by the TLB and so is a host address.
- In the TLB miss case, it continues to hold a guest address.
+ First argument register is loaded with the low part of the address.
+ In the TLB hit case, it has been adjusted as indicated by the TLB
+ and so is a host address. In the TLB miss case, it continues to
+ hold a guest address.
- EDX is clobbered. */
+ Second argument register is clobbered. */
static inline void tcg_out_tlb_load(TCGContext *s, int addrlo_idx,
int mem_index, int s_bits,
@@ -730,32 +1002,42 @@ static inline void tcg_out_tlb_load(TCGContext *s, int addrlo_idx,
uint8_t **label_ptr, int which)
{
const int addrlo = args[addrlo_idx];
- const int r0 = TCG_REG_EAX;
- const int r1 = TCG_REG_EDX;
+ const int r0 = tcg_target_call_iarg_regs[0];
+ const int r1 = tcg_target_call_iarg_regs[1];
+ TCGType type = TCG_TYPE_I32;
+ int rexw = 0;
+
+ if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 64) {
+ type = TCG_TYPE_I64;
+ rexw = P_REXW;
+ }
- tcg_out_mov(s, r1, addrlo);
- tcg_out_mov(s, r0, addrlo);
+ tcg_out_mov(s, type, r1, addrlo);
+ tcg_out_mov(s, type, r0, addrlo);
- tcg_out_shifti(s, SHIFT_SHR, r1, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
+ tcg_out_shifti(s, SHIFT_SHR + rexw, r1,
+ TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
- tgen_arithi(s, ARITH_AND, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1), 0);
- tgen_arithi(s, ARITH_AND, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, 0);
+ tgen_arithi(s, ARITH_AND + rexw, r0,
+ TARGET_PAGE_MASK | ((1 << s_bits) - 1), 0);
+ tgen_arithi(s, ARITH_AND + rexw, r1,
+ (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, 0);
- tcg_out_modrm_sib_offset(s, OPC_LEA, r1, TCG_AREG0, r1, 0,
+ tcg_out_modrm_sib_offset(s, OPC_LEA + P_REXW, r1, TCG_AREG0, r1, 0,
offsetof(CPUState, tlb_table[mem_index][0])
+ which);
/* cmp 0(r1), r0 */
- tcg_out_modrm_offset(s, OPC_CMP_GvEv, r0, r1, 0);
+ tcg_out_modrm_offset(s, OPC_CMP_GvEv + rexw, r0, r1, 0);
- tcg_out_mov(s, r0, addrlo);
+ tcg_out_mov(s, type, r0, addrlo);
/* jne label1 */
tcg_out8(s, OPC_JCC_short + JCC_JNE);
label_ptr[0] = s->code_ptr;
s->code_ptr++;
- if (TARGET_LONG_BITS == 64) {
+ if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
/* cmp 4(r1), addrhi */
tcg_out_modrm_offset(s, OPC_CMP_GvEv, args[addrlo_idx+1], r1, 4);
@@ -768,7 +1050,7 @@ static inline void tcg_out_tlb_load(TCGContext *s, int addrlo_idx,
/* TLB Hit. */
/* add addend(r1), r0 */
- tcg_out_modrm_offset(s, OPC_ADD_GvEv, r0, r1,
+ tcg_out_modrm_offset(s, OPC_ADD_GvEv + P_REXW, r0, r1,
offsetof(CPUTLBEntry, addend) - which);
}
#endif
@@ -783,26 +1065,24 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, int datalo, int datahi,
#endif
switch (sizeop) {
case 0:
- /* movzbl */
tcg_out_modrm_offset(s, OPC_MOVZBL, datalo, base, ofs);
break;
case 0 | 4:
- /* movsbl */
- tcg_out_modrm_offset(s, OPC_MOVSBL, datalo, base, ofs);
+ tcg_out_modrm_offset(s, OPC_MOVSBL + P_REXW, datalo, base, ofs);
break;
case 1:
- /* movzwl */
tcg_out_modrm_offset(s, OPC_MOVZWL, datalo, base, ofs);
if (bswap) {
tcg_out_rolw_8(s, datalo);
}
break;
case 1 | 4:
- /* movswl */
- tcg_out_modrm_offset(s, OPC_MOVSWL, datalo, base, ofs);
if (bswap) {
+ tcg_out_modrm_offset(s, OPC_MOVZWL, datalo, base, ofs);
tcg_out_rolw_8(s, datalo);
- tcg_out_modrm(s, OPC_MOVSWL, datalo, datalo);
+ tcg_out_modrm(s, OPC_MOVSWL + P_REXW, datalo, datalo);
+ } else {
+ tcg_out_modrm_offset(s, OPC_MOVSWL + P_REXW, datalo, base, ofs);
}
break;
case 2:
@@ -811,22 +1091,40 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, int datalo, int datahi,
tcg_out_bswap32(s, datalo);
}
break;
- case 3:
+#if TCG_TARGET_REG_BITS == 64
+ case 2 | 4:
if (bswap) {
- int t = datalo;
- datalo = datahi;
- datahi = t;
- }
- if (base != datalo) {
tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs);
- tcg_out_ld(s, TCG_TYPE_I32, datahi, base, ofs + 4);
+ tcg_out_bswap32(s, datalo);
+ tcg_out_ext32s(s, datalo, datalo);
} else {
- tcg_out_ld(s, TCG_TYPE_I32, datahi, base, ofs + 4);
- tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs);
+ tcg_out_modrm_offset(s, OPC_MOVSLQ, datalo, base, ofs);
}
- if (bswap) {
- tcg_out_bswap32(s, datalo);
- tcg_out_bswap32(s, datahi);
+ break;
+#endif
+ case 3:
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_out_ld(s, TCG_TYPE_I64, datalo, base, ofs);
+ if (bswap) {
+ tcg_out_bswap64(s, datalo);
+ }
+ } else {
+ if (bswap) {
+ int t = datalo;
+ datalo = datahi;
+ datahi = t;
+ }
+ if (base != datalo) {
+ tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs);
+ tcg_out_ld(s, TCG_TYPE_I32, datahi, base, ofs + 4);
+ } else {
+ tcg_out_ld(s, TCG_TYPE_I32, datahi, base, ofs + 4);
+ tcg_out_ld(s, TCG_TYPE_I32, datalo, base, ofs);
+ }
+ if (bswap) {
+ tcg_out_bswap32(s, datalo);
+ tcg_out_bswap32(s, datahi);
+ }
}
break;
default:
@@ -849,20 +1147,21 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
data_reg = args[0];
addrlo_idx = 1;
- if (opc == 3) {
+ if (TCG_TARGET_REG_BITS == 32 && opc == 3) {
data_reg2 = args[1];
addrlo_idx = 2;
}
#if defined(CONFIG_SOFTMMU)
- mem_index = args[addrlo_idx + (TARGET_LONG_BITS / 32)];
+ mem_index = args[addrlo_idx + 1 + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS)];
s_bits = opc & 3;
tcg_out_tlb_load(s, addrlo_idx, mem_index, s_bits, args,
label_ptr, offsetof(CPUTLBEntry, addr_read));
/* TLB Hit. */
- tcg_out_qemu_ld_direct(s, data_reg, data_reg2, TCG_REG_EAX, 0, opc);
+ tcg_out_qemu_ld_direct(s, data_reg, data_reg2,
+ tcg_target_call_iarg_regs[0], 0, opc);
/* jmp label2 */
tcg_out8(s, OPC_JMP_short);
@@ -873,15 +1172,15 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
/* label1: */
*label_ptr[0] = s->code_ptr - label_ptr[0] - 1;
- if (TARGET_LONG_BITS == 64) {
+ if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
*label_ptr[1] = s->code_ptr - label_ptr[1] - 1;
}
/* XXX: move that code at the end of the TB */
- /* EAX is already loaded. */
+ /* The first argument is already loaded with addrlo. */
arg_idx = 1;
- if (TARGET_LONG_BITS == 64) {
- tcg_out_mov(s, tcg_target_call_iarg_regs[arg_idx++],
+ if (TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 64) {
+ tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[arg_idx++],
args[addrlo_idx + 1]);
}
tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[arg_idx],
@@ -890,10 +1189,10 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
switch(opc) {
case 0 | 4:
- tcg_out_ext8s(s, data_reg, TCG_REG_EAX);
+ tcg_out_ext8s(s, data_reg, TCG_REG_EAX, P_REXW);
break;
case 1 | 4:
- tcg_out_ext16s(s, data_reg, TCG_REG_EAX);
+ tcg_out_ext16s(s, data_reg, TCG_REG_EAX, P_REXW);
break;
case 0:
tcg_out_ext8u(s, data_reg, TCG_REG_EAX);
@@ -902,26 +1201,52 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
tcg_out_ext16u(s, data_reg, TCG_REG_EAX);
break;
case 2:
- default:
- tcg_out_mov(s, data_reg, TCG_REG_EAX);
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg, TCG_REG_EAX);
+ break;
+#if TCG_TARGET_REG_BITS == 64
+ case 2 | 4:
+ tcg_out_ext32s(s, data_reg, TCG_REG_EAX);
break;
+#endif
case 3:
- if (data_reg == TCG_REG_EDX) {
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_out_mov(s, TCG_TYPE_I64, data_reg, TCG_REG_RAX);
+ } else if (data_reg == TCG_REG_EDX) {
/* xchg %edx, %eax */
- tcg_out_opc(s, OPC_XCHG_ax_r32 + TCG_REG_EDX);
- tcg_out_mov(s, data_reg2, TCG_REG_EAX);
+ tcg_out_opc(s, OPC_XCHG_ax_r32 + TCG_REG_EDX, 0, 0, 0);
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg2, TCG_REG_EAX);
} else {
- tcg_out_mov(s, data_reg, TCG_REG_EAX);
- tcg_out_mov(s, data_reg2, TCG_REG_EDX);
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg, TCG_REG_EAX);
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg2, TCG_REG_EDX);
}
break;
+ default:
+ tcg_abort();
}
/* label2: */
*label_ptr[2] = s->code_ptr - label_ptr[2] - 1;
#else
- tcg_out_qemu_ld_direct(s, data_reg, data_reg2,
- args[addrlo_idx], GUEST_BASE, opc);
+ {
+ int32_t offset = GUEST_BASE;
+ int base = args[addrlo_idx];
+
+ if (TCG_TARGET_REG_BITS == 64) {
+ /* ??? We assume all operations have left us with register
+ contents that are zero extended. So far this appears to
+ be true. If we want to enforce this, we can either do
+ an explicit zero-extension here, or (if GUEST_BASE == 0)
+ use the ADDR32 prefix. For now, do nothing. */
+
+ if (offset != GUEST_BASE) {
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_RDI, GUEST_BASE);
+ tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_RDI, base);
+ base = TCG_REG_RDI, offset = 0;
+ }
+ }
+
+ tcg_out_qemu_ld_direct(s, data_reg, data_reg2, base, offset, opc);
+ }
#endif
}
@@ -936,37 +1261,42 @@ static void tcg_out_qemu_st_direct(TCGContext *s, int datalo, int datahi,
/* ??? Ideally we wouldn't need a scratch register. For user-only,
we could perform the bswap twice to restore the original value
instead of moving to the scratch. But as it is, the L constraint
- means that EDX is definitely free here. */
- int scratch = TCG_REG_EDX;
+ means that the second argument reg is definitely free here. */
+ int scratch = tcg_target_call_iarg_regs[1];
switch (sizeop) {
case 0:
- tcg_out_modrm_offset(s, OPC_MOVB_EvGv, datalo, base, ofs);
+ tcg_out_modrm_offset(s, OPC_MOVB_EvGv + P_REXB_R, datalo, base, ofs);
break;
case 1:
if (bswap) {
- tcg_out_mov(s, scratch, datalo);
+ tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo);
tcg_out_rolw_8(s, scratch);
datalo = scratch;
}
- /* movw */
- tcg_out_modrm_offset(s, OPC_MOVL_EvGv | P_DATA16,
- datalo, base, ofs);
+ tcg_out_modrm_offset(s, OPC_MOVL_EvGv + P_DATA16, datalo, base, ofs);
break;
case 2:
if (bswap) {
- tcg_out_mov(s, scratch, datalo);
+ tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo);
tcg_out_bswap32(s, scratch);
datalo = scratch;
}
tcg_out_st(s, TCG_TYPE_I32, datalo, base, ofs);
break;
case 3:
- if (bswap) {
- tcg_out_mov(s, scratch, datahi);
+ if (TCG_TARGET_REG_BITS == 64) {
+ if (bswap) {
+ tcg_out_mov(s, TCG_TYPE_I64, scratch, datalo);
+ tcg_out_bswap64(s, scratch);
+ datalo = scratch;
+ }
+ tcg_out_st(s, TCG_TYPE_I64, datalo, base, ofs);
+ } else if (bswap) {
+ tcg_out_mov(s, TCG_TYPE_I32, scratch, datahi);
tcg_out_bswap32(s, scratch);
tcg_out_st(s, TCG_TYPE_I32, scratch, base, ofs);
- tcg_out_mov(s, scratch, datalo);
+ tcg_out_mov(s, TCG_TYPE_I32, scratch, datalo);
tcg_out_bswap32(s, scratch);
tcg_out_st(s, TCG_TYPE_I32, scratch, base, ofs + 4);
} else {
@@ -992,20 +1322,21 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
data_reg = args[0];
addrlo_idx = 1;
- if (opc == 3) {
+ if (TCG_TARGET_REG_BITS == 32 && opc == 3) {
data_reg2 = args[1];
addrlo_idx = 2;
}
#if defined(CONFIG_SOFTMMU)
- mem_index = args[addrlo_idx + (TARGET_LONG_BITS / 32)];
+ mem_index = args[addrlo_idx + 1 + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS)];
s_bits = opc;
tcg_out_tlb_load(s, addrlo_idx, mem_index, s_bits, args,
label_ptr, offsetof(CPUTLBEntry, addr_write));
/* TLB Hit. */
- tcg_out_qemu_st_direct(s, data_reg, data_reg2, TCG_REG_EAX, 0, opc);
+ tcg_out_qemu_st_direct(s, data_reg, data_reg2,
+ tcg_target_call_iarg_regs[0], 0, opc);
/* jmp label2 */
tcg_out8(s, OPC_JMP_short);
@@ -1016,15 +1347,20 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
/* label1: */
*label_ptr[0] = s->code_ptr - label_ptr[0] - 1;
- if (TARGET_LONG_BITS == 64) {
+ if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) {
*label_ptr[1] = s->code_ptr - label_ptr[1] - 1;
}
/* XXX: move that code at the end of the TB */
- if (TARGET_LONG_BITS == 32) {
- tcg_out_mov(s, TCG_REG_EDX, data_reg);
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32),
+ TCG_REG_RSI, data_reg);
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index);
+ stack_adjust = 0;
+ } else if (TARGET_LONG_BITS == 32) {
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, data_reg);
if (opc == 3) {
- tcg_out_mov(s, TCG_REG_ECX, data_reg2);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_ECX, data_reg2);
tcg_out_pushi(s, mem_index);
stack_adjust = 4;
} else {
@@ -1033,13 +1369,13 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
}
} else {
if (opc == 3) {
- tcg_out_mov(s, TCG_REG_EDX, args[addrlo_idx + 1]);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, args[addrlo_idx + 1]);
tcg_out_pushi(s, mem_index);
tcg_out_push(s, data_reg2);
tcg_out_push(s, data_reg);
stack_adjust = 12;
} else {
- tcg_out_mov(s, TCG_REG_EDX, args[addrlo_idx + 1]);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_EDX, args[addrlo_idx + 1]);
switch(opc) {
case 0:
tcg_out_ext8u(s, TCG_REG_ECX, data_reg);
@@ -1048,7 +1384,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
tcg_out_ext16u(s, TCG_REG_ECX, data_reg);
break;
case 2:
- tcg_out_mov(s, TCG_REG_ECX, data_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_ECX, data_reg);
break;
}
tcg_out_pushi(s, mem_index);
@@ -1058,7 +1394,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
tcg_out_calli(s, (tcg_target_long)qemu_st_helpers[s_bits]);
- if (stack_adjust == 4) {
+ if (stack_adjust == (TCG_TARGET_REG_BITS / 8)) {
/* Pop and discard. This is 2 bytes smaller than the add. */
tcg_out_pop(s, TCG_REG_ECX);
} else if (stack_adjust != 0) {
@@ -1068,21 +1404,48 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
/* label2: */
*label_ptr[2] = s->code_ptr - label_ptr[2] - 1;
#else
- tcg_out_qemu_st_direct(s, data_reg, data_reg2,
- args[addrlo_idx], GUEST_BASE, opc);
+ {
+ int32_t offset = GUEST_BASE;
+ int base = args[addrlo_idx];
+
+ if (TCG_TARGET_REG_BITS == 64) {
+ /* ??? We assume all operations have left us with register
+ contents that are zero extended. So far this appears to
+ be true. If we want to enforce this, we can either do
+ an explicit zero-extension here, or (if GUEST_BASE == 0)
+ use the ADDR32 prefix. For now, do nothing. */
+
+ if (offset != GUEST_BASE) {
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_RDI, GUEST_BASE);
+ tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_RDI, base);
+ base = TCG_REG_RDI, offset = 0;
+ }
+ }
+
+ tcg_out_qemu_st_direct(s, data_reg, data_reg2, base, offset, opc);
+ }
#endif
}
static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
const TCGArg *args, const int *const_args)
{
- int c;
+ int c, rexw = 0;
+
+#if TCG_TARGET_REG_BITS == 64
+# define OP_32_64(x) \
+ case glue(glue(INDEX_op_, x), _i64): \
+ rexw = P_REXW; /* FALLTHRU */ \
+ case glue(glue(INDEX_op_, x), _i32)
+#else
+# define OP_32_64(x) \
+ case glue(glue(INDEX_op_, x), _i32)
+#endif
switch(opc) {
case INDEX_op_exit_tb:
- tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EAX, args[0]);
- tcg_out8(s, OPC_JMP_long); /* jmp tb_ret_addr */
- tcg_out32(s, tb_ret_addr - s->code_ptr - 4);
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_EAX, args[0]);
+ tcg_out_jmp(s, (tcg_target_long) tb_ret_addr);
break;
case INDEX_op_goto_tb:
if (s->tb_jmp_offset) {
@@ -1107,8 +1470,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
break;
case INDEX_op_jmp:
if (const_args[0]) {
- tcg_out8(s, OPC_JMP_long);
- tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4);
+ tcg_out_jmp(s, args[0]);
} else {
/* jmp *reg */
tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, args[0]);
@@ -1120,38 +1482,43 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
case INDEX_op_movi_i32:
tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
break;
- case INDEX_op_ld8u_i32:
- /* movzbl */
+ OP_32_64(ld8u):
+ /* Note that we can ignore REXW for the zero-extend to 64-bit. */
tcg_out_modrm_offset(s, OPC_MOVZBL, args[0], args[1], args[2]);
break;
- case INDEX_op_ld8s_i32:
- /* movsbl */
- tcg_out_modrm_offset(s, OPC_MOVSBL, args[0], args[1], args[2]);
+ OP_32_64(ld8s):
+ tcg_out_modrm_offset(s, OPC_MOVSBL + rexw, args[0], args[1], args[2]);
break;
- case INDEX_op_ld16u_i32:
- /* movzwl */
+ OP_32_64(ld16u):
+ /* Note that we can ignore REXW for the zero-extend to 64-bit. */
tcg_out_modrm_offset(s, OPC_MOVZWL, args[0], args[1], args[2]);
break;
- case INDEX_op_ld16s_i32:
- /* movswl */
- tcg_out_modrm_offset(s, OPC_MOVSWL, args[0], args[1], args[2]);
+ OP_32_64(ld16s):
+ tcg_out_modrm_offset(s, OPC_MOVSWL + rexw, args[0], args[1], args[2]);
break;
+#if TCG_TARGET_REG_BITS == 64
+ case INDEX_op_ld32u_i64:
+#endif
case INDEX_op_ld_i32:
tcg_out_ld(s, TCG_TYPE_I32, args[0], args[1], args[2]);
break;
- case INDEX_op_st8_i32:
- /* movb */
- tcg_out_modrm_offset(s, OPC_MOVB_EvGv, args[0], args[1], args[2]);
+
+ OP_32_64(st8):
+ tcg_out_modrm_offset(s, OPC_MOVB_EvGv | P_REXB_R,
+ args[0], args[1], args[2]);
break;
- case INDEX_op_st16_i32:
- /* movw */
+ OP_32_64(st16):
tcg_out_modrm_offset(s, OPC_MOVL_EvGv | P_DATA16,
args[0], args[1], args[2]);
break;
+#if TCG_TARGET_REG_BITS == 64
+ case INDEX_op_st32_i64:
+#endif
case INDEX_op_st_i32:
tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]);
break;
- case INDEX_op_add_i32:
+
+ OP_32_64(add):
/* For 3-operand addition, use LEA. */
if (args[0] != args[1]) {
TCGArg a0 = args[0], a1 = args[1], a2 = args[2], c3 = 0;
@@ -1161,147 +1528,117 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
} else if (a0 == a2) {
/* Watch out for dest = src + dest, since we've removed
the matching constraint on the add. */
- tgen_arithr(s, ARITH_ADD, a0, a1);
+ tgen_arithr(s, ARITH_ADD + rexw, a0, a1);
break;
}
- tcg_out_modrm_sib_offset(s, OPC_LEA, a0, a1, a2, 0, c3);
+ tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, a1, a2, 0, c3);
break;
}
c = ARITH_ADD;
goto gen_arith;
- case INDEX_op_sub_i32:
+ OP_32_64(sub):
c = ARITH_SUB;
goto gen_arith;
- case INDEX_op_and_i32:
+ OP_32_64(and):
c = ARITH_AND;
goto gen_arith;
- case INDEX_op_or_i32:
+ OP_32_64(or):
c = ARITH_OR;
goto gen_arith;
- case INDEX_op_xor_i32:
+ OP_32_64(xor):
c = ARITH_XOR;
goto gen_arith;
gen_arith:
if (const_args[2]) {
- tgen_arithi(s, c, args[0], args[2], 0);
+ tgen_arithi(s, c + rexw, args[0], args[2], 0);
} else {
- tgen_arithr(s, c, args[0], args[2]);
+ tgen_arithr(s, c + rexw, args[0], args[2]);
}
break;
- case INDEX_op_mul_i32:
+
+ OP_32_64(mul):
if (const_args[2]) {
int32_t val;
val = args[2];
if (val == (int8_t)val) {
- tcg_out_modrm(s, OPC_IMUL_GvEvIb, args[0], args[0]);
+ tcg_out_modrm(s, OPC_IMUL_GvEvIb + rexw, args[0], args[0]);
tcg_out8(s, val);
} else {
- tcg_out_modrm(s, OPC_IMUL_GvEvIz, args[0], args[0]);
+ tcg_out_modrm(s, OPC_IMUL_GvEvIz + rexw, args[0], args[0]);
tcg_out32(s, val);
}
} else {
- tcg_out_modrm(s, OPC_IMUL_GvEv, args[0], args[2]);
+ tcg_out_modrm(s, OPC_IMUL_GvEv + rexw, args[0], args[2]);
}
break;
- case INDEX_op_mulu2_i32:
- tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_MUL, args[3]);
- break;
- case INDEX_op_div2_i32:
- tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_IDIV, args[4]);
+
+ OP_32_64(div2):
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IDIV, args[4]);
break;
- case INDEX_op_divu2_i32:
- tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_DIV, args[4]);
+ OP_32_64(divu2):
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_DIV, args[4]);
break;
- case INDEX_op_shl_i32:
+
+ OP_32_64(shl):
c = SHIFT_SHL;
- gen_shift32:
- if (const_args[2]) {
- tcg_out_shifti(s, c, args[0], args[2]);
- } else {
- tcg_out_modrm(s, OPC_SHIFT_cl, c, args[0]);
- }
- break;
- case INDEX_op_shr_i32:
+ goto gen_shift;
+ OP_32_64(shr):
c = SHIFT_SHR;
- goto gen_shift32;
- case INDEX_op_sar_i32:
+ goto gen_shift;
+ OP_32_64(sar):
c = SHIFT_SAR;
- goto gen_shift32;
- case INDEX_op_rotl_i32:
+ goto gen_shift;
+ OP_32_64(rotl):
c = SHIFT_ROL;
- goto gen_shift32;
- case INDEX_op_rotr_i32:
+ goto gen_shift;
+ OP_32_64(rotr):
c = SHIFT_ROR;
- goto gen_shift32;
-
- case INDEX_op_add2_i32:
- if (const_args[4]) {
- tgen_arithi(s, ARITH_ADD, args[0], args[4], 1);
- } else {
- tgen_arithr(s, ARITH_ADD, args[0], args[4]);
- }
- if (const_args[5]) {
- tgen_arithi(s, ARITH_ADC, args[1], args[5], 1);
+ goto gen_shift;
+ gen_shift:
+ if (const_args[2]) {
+ tcg_out_shifti(s, c + rexw, args[0], args[2]);
} else {
- tgen_arithr(s, ARITH_ADC, args[1], args[5]);
- }
- break;
- case INDEX_op_sub2_i32:
- if (const_args[4]) {
- tgen_arithi(s, ARITH_SUB, args[0], args[4], 1);
- } else {
- tgen_arithr(s, ARITH_SUB, args[0], args[4]);
- }
- if (const_args[5]) {
- tgen_arithi(s, ARITH_SBB, args[1], args[5], 1);
- } else {
- tgen_arithr(s, ARITH_SBB, args[1], args[5]);
+ tcg_out_modrm(s, OPC_SHIFT_cl + rexw, c, args[0]);
}
break;
+
case INDEX_op_brcond_i32:
- tcg_out_brcond(s, args[2], args[0], args[1], const_args[1],
- args[3], 0);
+ tcg_out_brcond32(s, args[2], args[0], args[1], const_args[1],
+ args[3], 0);
break;
- case INDEX_op_brcond2_i32:
- tcg_out_brcond2(s, args, const_args, 0);
+ case INDEX_op_setcond_i32:
+ tcg_out_setcond32(s, args[3], args[0], args[1],
+ args[2], const_args[2]);
break;
- case INDEX_op_bswap16_i32:
+ OP_32_64(bswap16):
tcg_out_rolw_8(s, args[0]);
break;
- case INDEX_op_bswap32_i32:
+ OP_32_64(bswap32):
tcg_out_bswap32(s, args[0]);
break;
- case INDEX_op_neg_i32:
- tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_NEG, args[0]);
+ OP_32_64(neg):
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NEG, args[0]);
break;
-
- case INDEX_op_not_i32:
- tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_NOT, args[0]);
+ OP_32_64(not):
+ tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, args[0]);
break;
- case INDEX_op_ext8s_i32:
- tcg_out_ext8s(s, args[0], args[1]);
+ OP_32_64(ext8s):
+ tcg_out_ext8s(s, args[0], args[1], rexw);
break;
- case INDEX_op_ext16s_i32:
- tcg_out_ext16s(s, args[0], args[1]);
+ OP_32_64(ext16s):
+ tcg_out_ext16s(s, args[0], args[1], rexw);
break;
- case INDEX_op_ext8u_i32:
+ OP_32_64(ext8u):
tcg_out_ext8u(s, args[0], args[1]);
break;
- case INDEX_op_ext16u_i32:
+ OP_32_64(ext16u):
tcg_out_ext16u(s, args[0], args[1]);
break;
- case INDEX_op_setcond_i32:
- tcg_out_setcond(s, args[3], args[0], args[1], args[2], const_args[2]);
- break;
- case INDEX_op_setcond2_i32:
- tcg_out_setcond2(s, args, const_args);
- break;
-
case INDEX_op_qemu_ld8u:
tcg_out_qemu_ld(s, args, 0);
break;
@@ -1314,6 +1651,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
case INDEX_op_qemu_ld16s:
tcg_out_qemu_ld(s, args, 1 | 4);
break;
+#if TCG_TARGET_REG_BITS == 64
+ case INDEX_op_qemu_ld32u:
+#endif
case INDEX_op_qemu_ld32:
tcg_out_qemu_ld(s, args, 2);
break;
@@ -1334,9 +1674,82 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
tcg_out_qemu_st(s, args, 3);
break;
+#if TCG_TARGET_REG_BITS == 32
+ case INDEX_op_brcond2_i32:
+ tcg_out_brcond2(s, args, const_args, 0);
+ break;
+ case INDEX_op_setcond2_i32:
+ tcg_out_setcond2(s, args, const_args);
+ break;
+ case INDEX_op_mulu2_i32:
+ tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_MUL, args[3]);
+ break;
+ case INDEX_op_add2_i32:
+ if (const_args[4]) {
+ tgen_arithi(s, ARITH_ADD, args[0], args[4], 1);
+ } else {
+ tgen_arithr(s, ARITH_ADD, args[0], args[4]);
+ }
+ if (const_args[5]) {
+ tgen_arithi(s, ARITH_ADC, args[1], args[5], 1);
+ } else {
+ tgen_arithr(s, ARITH_ADC, args[1], args[5]);
+ }
+ break;
+ case INDEX_op_sub2_i32:
+ if (const_args[4]) {
+ tgen_arithi(s, ARITH_SUB, args[0], args[4], 1);
+ } else {
+ tgen_arithr(s, ARITH_SUB, args[0], args[4]);
+ }
+ if (const_args[5]) {
+ tgen_arithi(s, ARITH_SBB, args[1], args[5], 1);
+ } else {
+ tgen_arithr(s, ARITH_SBB, args[1], args[5]);
+ }
+ break;
+#else /* TCG_TARGET_REG_BITS == 64 */
+ case INDEX_op_movi_i64:
+ tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
+ break;
+ case INDEX_op_ld32s_i64:
+ tcg_out_modrm_offset(s, OPC_MOVSLQ, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_ld_i64:
+ tcg_out_ld(s, TCG_TYPE_I64, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_st_i64:
+ tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]);
+ break;
+ case INDEX_op_qemu_ld32s:
+ tcg_out_qemu_ld(s, args, 2 | 4);
+ break;
+
+ case INDEX_op_brcond_i64:
+ tcg_out_brcond64(s, args[2], args[0], args[1], const_args[1],
+ args[3], 0);
+ break;
+ case INDEX_op_setcond_i64:
+ tcg_out_setcond64(s, args[3], args[0], args[1],
+ args[2], const_args[2]);
+ break;
+
+ case INDEX_op_bswap64_i64:
+ tcg_out_bswap64(s, args[0]);
+ break;
+ case INDEX_op_ext32u_i64:
+ tcg_out_ext32u(s, args[0], args[1]);
+ break;
+ case INDEX_op_ext32s_i64:
+ tcg_out_ext32s(s, args[0], args[1]);
+ break;
+#endif
+
default:
tcg_abort();
}
+
+#undef OP_32_64
}
static const TCGTargetOpDef x86_op_defs[] = {
@@ -1359,7 +1772,6 @@ static const TCGTargetOpDef x86_op_defs[] = {
{ INDEX_op_add_i32, { "r", "r", "ri" } },
{ INDEX_op_sub_i32, { "r", "0", "ri" } },
{ INDEX_op_mul_i32, { "r", "0", "ri" } },
- { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } },
{ INDEX_op_div2_i32, { "a", "d", "0", "1", "r" } },
{ INDEX_op_divu2_i32, { "a", "d", "0", "1", "r" } },
{ INDEX_op_and_i32, { "r", "0", "ri" } },
@@ -1374,10 +1786,6 @@ static const TCGTargetOpDef x86_op_defs[] = {
{ INDEX_op_brcond_i32, { "r", "ri" } },
- { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } },
- { INDEX_op_sub2_i32, { "r", "r", "0", "1", "ri", "ri" } },
- { INDEX_op_brcond2_i32, { "r", "r", "ri", "ri" } },
-
{ INDEX_op_bswap16_i32, { "r", "0" } },
{ INDEX_op_bswap32_i32, { "r", "0" } },
@@ -1391,9 +1799,75 @@ static const TCGTargetOpDef x86_op_defs[] = {
{ INDEX_op_ext16u_i32, { "r", "r" } },
{ INDEX_op_setcond_i32, { "q", "r", "ri" } },
+
+#if TCG_TARGET_REG_BITS == 32
+ { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } },
+ { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } },
+ { INDEX_op_sub2_i32, { "r", "r", "0", "1", "ri", "ri" } },
+ { INDEX_op_brcond2_i32, { "r", "r", "ri", "ri" } },
{ INDEX_op_setcond2_i32, { "r", "r", "r", "ri", "ri" } },
+#else
+ { INDEX_op_mov_i64, { "r", "r" } },
+ { INDEX_op_movi_i64, { "r" } },
+ { INDEX_op_ld8u_i64, { "r", "r" } },
+ { INDEX_op_ld8s_i64, { "r", "r" } },
+ { INDEX_op_ld16u_i64, { "r", "r" } },
+ { INDEX_op_ld16s_i64, { "r", "r" } },
+ { INDEX_op_ld32u_i64, { "r", "r" } },
+ { INDEX_op_ld32s_i64, { "r", "r" } },
+ { INDEX_op_ld_i64, { "r", "r" } },
+ { INDEX_op_st8_i64, { "r", "r" } },
+ { INDEX_op_st16_i64, { "r", "r" } },
+ { INDEX_op_st32_i64, { "r", "r" } },
+ { INDEX_op_st_i64, { "r", "r" } },
+
+ { INDEX_op_add_i64, { "r", "0", "re" } },
+ { INDEX_op_mul_i64, { "r", "0", "re" } },
+ { INDEX_op_div2_i64, { "a", "d", "0", "1", "r" } },
+ { INDEX_op_divu2_i64, { "a", "d", "0", "1", "r" } },
+ { INDEX_op_sub_i64, { "r", "0", "re" } },
+ { INDEX_op_and_i64, { "r", "0", "reZ" } },
+ { INDEX_op_or_i64, { "r", "0", "re" } },
+ { INDEX_op_xor_i64, { "r", "0", "re" } },
+
+ { INDEX_op_shl_i64, { "r", "0", "ci" } },
+ { INDEX_op_shr_i64, { "r", "0", "ci" } },
+ { INDEX_op_sar_i64, { "r", "0", "ci" } },
+ { INDEX_op_rotl_i64, { "r", "0", "ci" } },
+ { INDEX_op_rotr_i64, { "r", "0", "ci" } },
+
+ { INDEX_op_brcond_i64, { "r", "re" } },
+ { INDEX_op_setcond_i64, { "r", "r", "re" } },
+
+ { INDEX_op_bswap16_i64, { "r", "0" } },
+ { INDEX_op_bswap32_i64, { "r", "0" } },
+ { INDEX_op_bswap64_i64, { "r", "0" } },
+ { INDEX_op_neg_i64, { "r", "0" } },
+ { INDEX_op_not_i64, { "r", "0" } },
+
+ { INDEX_op_ext8s_i64, { "r", "r" } },
+ { INDEX_op_ext16s_i64, { "r", "r" } },
+ { INDEX_op_ext32s_i64, { "r", "r" } },
+ { INDEX_op_ext8u_i64, { "r", "r" } },
+ { INDEX_op_ext16u_i64, { "r", "r" } },
+ { INDEX_op_ext32u_i64, { "r", "r" } },
+#endif
-#if TARGET_LONG_BITS == 32
+#if TCG_TARGET_REG_BITS == 64
+ { INDEX_op_qemu_ld8u, { "r", "L" } },
+ { INDEX_op_qemu_ld8s, { "r", "L" } },
+ { INDEX_op_qemu_ld16u, { "r", "L" } },
+ { INDEX_op_qemu_ld16s, { "r", "L" } },
+ { INDEX_op_qemu_ld32, { "r", "L" } },
+ { INDEX_op_qemu_ld32u, { "r", "L" } },
+ { INDEX_op_qemu_ld32s, { "r", "L" } },
+ { INDEX_op_qemu_ld64, { "r", "L" } },
+
+ { INDEX_op_qemu_st8, { "L", "L" } },
+ { INDEX_op_qemu_st16, { "L", "L" } },
+ { INDEX_op_qemu_st32, { "L", "L" } },
+ { INDEX_op_qemu_st64, { "L", "L" } },
+#elif TARGET_LONG_BITS <= TCG_TARGET_REG_BITS
{ INDEX_op_qemu_ld8u, { "r", "L" } },
{ INDEX_op_qemu_ld8s, { "r", "L" } },
{ INDEX_op_qemu_ld16u, { "r", "L" } },
@@ -1422,43 +1896,58 @@ static const TCGTargetOpDef x86_op_defs[] = {
};
static int tcg_target_callee_save_regs[] = {
- /* TCG_REG_EBP, */ /* currently used for the global env, so no
- need to save */
+#if TCG_TARGET_REG_BITS == 64
+ TCG_REG_RBP,
+ TCG_REG_RBX,
+ TCG_REG_R12,
+ TCG_REG_R13,
+ /* TCG_REG_R14, */ /* Currently used for the global env. */
+ TCG_REG_R15,
+#else
+ /* TCG_REG_EBP, */ /* Currently used for the global env. */
TCG_REG_EBX,
TCG_REG_ESI,
TCG_REG_EDI,
+#endif
};
/* Generate global QEMU prologue and epilogue code */
-void tcg_target_qemu_prologue(TCGContext *s)
+static void tcg_target_qemu_prologue(TCGContext *s)
{
int i, frame_size, push_size, stack_addend;
/* TB prologue */
- /* save all callee saved registers */
- for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
+
+ /* Save all callee saved registers. */
+ for (i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
tcg_out_push(s, tcg_target_callee_save_regs[i]);
}
- /* reserve some stack space */
- push_size = 4 + ARRAY_SIZE(tcg_target_callee_save_regs) * 4;
+
+ /* Reserve some stack space. */
+ push_size = 1 + ARRAY_SIZE(tcg_target_callee_save_regs);
+ push_size *= TCG_TARGET_REG_BITS / 8;
+
frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE;
frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
~(TCG_TARGET_STACK_ALIGN - 1);
stack_addend = frame_size - push_size;
tcg_out_addi(s, TCG_REG_ESP, -stack_addend);
- tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, TCG_REG_EAX); /* jmp *%eax */
+ /* jmp *tb. */
+ tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, tcg_target_call_iarg_regs[0]);
/* TB epilogue */
tb_ret_addr = s->code_ptr;
+
tcg_out_addi(s, TCG_REG_ESP, stack_addend);
- for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) {
+
+ for (i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) {
tcg_out_pop(s, tcg_target_callee_save_regs[i]);
}
- tcg_out_opc(s, OPC_RET);
+ tcg_out_opc(s, OPC_RET, 0, 0, 0);
}
-void tcg_target_init(TCGContext *s)
+static void tcg_target_init(TCGContext *s)
{
#if !defined(CONFIG_USER_ONLY)
/* fail safe */
@@ -1466,12 +1955,25 @@ void tcg_target_init(TCGContext *s)
tcg_abort();
#endif
- tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xff);
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff);
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff);
+ } else {
+ tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xff);
+ }
tcg_regset_clear(tcg_target_call_clobber_regs);
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_EAX);
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_EDX);
tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_ECX);
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RDI);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_RSI);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R8);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R9);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R10);
+ tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R11);
+ }
tcg_regset_clear(s->reserved_regs);
tcg_regset_set_reg(s->reserved_regs, TCG_REG_ESP);
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index ca1d730..bfafbfc 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -23,10 +23,18 @@
*/
#define TCG_TARGET_I386 1
-#define TCG_TARGET_REG_BITS 32
+#if defined(__x86_64__)
+# define TCG_TARGET_REG_BITS 64
+#else
+# define TCG_TARGET_REG_BITS 32
+#endif
//#define TCG_TARGET_WORDS_BIGENDIAN
-#define TCG_TARGET_NB_REGS 8
+#if TCG_TARGET_REG_BITS == 64
+# define TCG_TARGET_NB_REGS 16
+#else
+# define TCG_TARGET_NB_REGS 8
+#endif
enum {
TCG_REG_EAX = 0,
@@ -37,8 +45,30 @@ enum {
TCG_REG_EBP,
TCG_REG_ESI,
TCG_REG_EDI,
+
+ /* 64-bit registers; always define the symbols to avoid
+ too much if-deffing. */
+ TCG_REG_R8,
+ TCG_REG_R9,
+ TCG_REG_R10,
+ TCG_REG_R11,
+ TCG_REG_R12,
+ TCG_REG_R13,
+ TCG_REG_R14,
+ TCG_REG_R15,
+ TCG_REG_RAX = TCG_REG_EAX,
+ TCG_REG_RCX = TCG_REG_ECX,
+ TCG_REG_RDX = TCG_REG_EDX,
+ TCG_REG_RBX = TCG_REG_EBX,
+ TCG_REG_RSP = TCG_REG_ESP,
+ TCG_REG_RBP = TCG_REG_EBP,
+ TCG_REG_RSI = TCG_REG_ESI,
+ TCG_REG_RDI = TCG_REG_EDI,
};
+#define TCG_CT_CONST_S32 0x100
+#define TCG_CT_CONST_U32 0x200
+
/* used for function call generation */
#define TCG_REG_CALL_STACK TCG_REG_ESP
#define TCG_TARGET_STACK_ALIGN 16
@@ -61,10 +91,35 @@ enum {
// #define TCG_TARGET_HAS_nand_i32
// #define TCG_TARGET_HAS_nor_i32
+#if TCG_TARGET_REG_BITS == 64
+#define TCG_TARGET_HAS_div2_i64
+#define TCG_TARGET_HAS_rot_i64
+#define TCG_TARGET_HAS_ext8s_i64
+#define TCG_TARGET_HAS_ext16s_i64
+#define TCG_TARGET_HAS_ext32s_i64
+#define TCG_TARGET_HAS_ext8u_i64
+#define TCG_TARGET_HAS_ext16u_i64
+#define TCG_TARGET_HAS_ext32u_i64
+#define TCG_TARGET_HAS_bswap16_i64
+#define TCG_TARGET_HAS_bswap32_i64
+#define TCG_TARGET_HAS_bswap64_i64
+#define TCG_TARGET_HAS_neg_i64
+#define TCG_TARGET_HAS_not_i64
+// #define TCG_TARGET_HAS_andc_i64
+// #define TCG_TARGET_HAS_orc_i64
+// #define TCG_TARGET_HAS_eqv_i64
+// #define TCG_TARGET_HAS_nand_i64
+// #define TCG_TARGET_HAS_nor_i64
+#endif
+
#define TCG_TARGET_HAS_GUEST_BASE
/* Note: must be synced with dyngen-exec.h */
-#define TCG_AREG0 TCG_REG_EBP
+#if TCG_TARGET_REG_BITS == 64
+# define TCG_AREG0 TCG_REG_R14
+#else
+# define TCG_AREG0 TCG_REG_EBP
+#endif
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index 905f48b..a0f3877 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -827,7 +827,8 @@ static inline void tcg_out_bundle(TCGContext *s, int template,
s->code_ptr += 16;
}
-static inline void tcg_out_mov(TCGContext *s, TCGArg ret, TCGArg arg)
+static inline void tcg_out_mov(TCGContext *s, TCGType type,
+ TCGArg ret, TCGArg arg)
{
tcg_out_bundle(s, mmI,
tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
@@ -2265,7 +2266,7 @@ static const TCGTargetOpDef ia64_op_defs[] = {
};
/* Generate global QEMU prologue and epilogue code */
-void tcg_target_qemu_prologue(TCGContext *s)
+static void tcg_target_qemu_prologue(TCGContext *s)
{
int frame_size;
@@ -2320,7 +2321,7 @@ void tcg_target_qemu_prologue(TCGContext *s)
TCG_REG_B0));
}
-void tcg_target_init(TCGContext *s)
+static void tcg_target_init(TCGContext *s)
{
tcg_regset_set(tcg_target_available_regs[TCG_TYPE_I32],
0xffffffffffffffffull);
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index f38eb28..2af7a2e 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.c
@@ -377,7 +377,7 @@ static inline void tcg_out_nop(TCGContext *s)
tcg_out32(s, 0);
}
-static inline void tcg_out_mov(TCGContext *s, int ret, int arg)
+static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
{
tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO);
}
@@ -849,9 +849,9 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
/* slow path */
sp_args = TCG_REG_A0;
- tcg_out_mov(s, sp_args++, addr_reg1);
+ tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg1);
# if TARGET_LONG_BITS == 64
- tcg_out_mov(s, sp_args++, addr_reg2);
+ tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg2);
# endif
tcg_out_movi(s, TCG_TYPE_I32, sp_args++, mem_index);
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_ld_helpers[s_bits]);
@@ -872,11 +872,11 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
tcg_out_ext16s(s, data_reg1, TCG_REG_V0);
break;
case 2:
- tcg_out_mov(s, data_reg1, TCG_REG_V0);
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg1, TCG_REG_V0);
break;
case 3:
- tcg_out_mov(s, data_reg2, TCG_REG_V1);
- tcg_out_mov(s, data_reg1, TCG_REG_V0);
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg2, TCG_REG_V1);
+ tcg_out_mov(s, TCG_TYPE_I32, data_reg1, TCG_REG_V0);
break;
default:
tcg_abort();
@@ -1035,9 +1035,9 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
/* slow path */
sp_args = TCG_REG_A0;
- tcg_out_mov(s, sp_args++, addr_reg1);
+ tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg1);
# if TARGET_LONG_BITS == 64
- tcg_out_mov(s, sp_args++, addr_reg2);
+ tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg2);
# endif
switch(opc) {
case 0:
@@ -1047,12 +1047,12 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xffff);
break;
case 2:
- tcg_out_mov(s, sp_args++, data_reg1);
+ tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg1);
break;
case 3:
sp_args = (sp_args + 1) & ~1;
- tcg_out_mov(s, sp_args++, data_reg1);
- tcg_out_mov(s, sp_args++, data_reg2);
+ tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg1);
+ tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg2);
break;
default:
tcg_abort();
@@ -1165,7 +1165,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
break;
case INDEX_op_mov_i32:
- tcg_out_mov(s, args[0], args[1]);
+ tcg_out_mov(s, TCG_TYPE_I32, args[0], args[1]);
break;
case INDEX_op_movi_i32:
tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
@@ -1216,7 +1216,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
tcg_out_opc_reg(s, OPC_ADDU, args[1], args[3], args[5]);
}
tcg_out_opc_reg(s, OPC_ADDU, args[1], args[1], TCG_REG_T0);
- tcg_out_mov(s, args[0], TCG_REG_AT);
+ tcg_out_mov(s, TCG_TYPE_I32, args[0], TCG_REG_AT);
break;
case INDEX_op_sub_i32:
if (const_args[2]) {
@@ -1238,7 +1238,7 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
tcg_out_opc_reg(s, OPC_SUBU, args[1], args[3], args[5]);
}
tcg_out_opc_reg(s, OPC_SUBU, args[1], args[1], TCG_REG_T0);
- tcg_out_mov(s, args[0], TCG_REG_AT);
+ tcg_out_mov(s, TCG_TYPE_I32, args[0], TCG_REG_AT);
break;
case INDEX_op_mul_i32:
tcg_out_opc_reg(s, OPC_MULT, 0, args[1], args[2]);
@@ -1466,7 +1466,7 @@ static int tcg_target_callee_save_regs[] = {
};
/* Generate global QEMU prologue and epilogue code */
-void tcg_target_qemu_prologue(TCGContext *s)
+static void tcg_target_qemu_prologue(TCGContext *s)
{
int i, frame_size;
@@ -1498,7 +1498,7 @@ void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_addi(s, TCG_REG_SP, frame_size);
}
-void tcg_target_init(TCGContext *s)
+static void tcg_target_init(TCGContext *s)
{
tcg_regset_set(tcg_target_available_regs[TCG_TYPE_I32], 0xffffffff);
tcg_regset_set(tcg_target_call_clobber_regs,
diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c
index 2b85928..2e5bb9f 100644
--- a/tcg/ppc/tcg-target.c
+++ b/tcg/ppc/tcg-target.c
@@ -437,7 +437,7 @@ static const uint32_t tcg_to_bc[10] = {
[TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE,
};
-static void tcg_out_mov(TCGContext *s, int ret, int arg)
+static void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
{
tcg_out32 (s, OR | SAB (arg, ret, arg));
}
@@ -591,11 +591,11 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
/* slow path */
#if TARGET_LONG_BITS == 32
- tcg_out_mov (s, 3, addr_reg);
+ tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg);
tcg_out_movi (s, TCG_TYPE_I32, 4, mem_index);
#else
- tcg_out_mov (s, 3, addr_reg2);
- tcg_out_mov (s, 4, addr_reg);
+ tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg2);
+ tcg_out_mov (s, TCG_TYPE_I32, 4, addr_reg);
tcg_out_movi (s, TCG_TYPE_I32, 5, mem_index);
#endif
@@ -611,23 +611,23 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
case 1:
case 2:
if (data_reg != 3)
- tcg_out_mov (s, data_reg, 3);
+ tcg_out_mov (s, TCG_TYPE_I32, data_reg, 3);
break;
case 3:
if (data_reg == 3) {
if (data_reg2 == 4) {
- tcg_out_mov (s, 0, 4);
- tcg_out_mov (s, 4, 3);
- tcg_out_mov (s, 3, 0);
+ tcg_out_mov (s, TCG_TYPE_I32, 0, 4);
+ tcg_out_mov (s, TCG_TYPE_I32, 4, 3);
+ tcg_out_mov (s, TCG_TYPE_I32, 3, 0);
}
else {
- tcg_out_mov (s, data_reg2, 3);
- tcg_out_mov (s, 3, 4);
+ tcg_out_mov (s, TCG_TYPE_I32, data_reg2, 3);
+ tcg_out_mov (s, TCG_TYPE_I32, 3, 4);
}
}
else {
- if (data_reg != 4) tcg_out_mov (s, data_reg, 4);
- if (data_reg2 != 3) tcg_out_mov (s, data_reg2, 3);
+ if (data_reg != 4) tcg_out_mov (s, TCG_TYPE_I32, data_reg, 4);
+ if (data_reg2 != 3) tcg_out_mov (s, TCG_TYPE_I32, data_reg2, 3);
}
break;
}
@@ -705,7 +705,7 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
if (r0 == data_reg2) {
tcg_out32 (s, LWZ | RT (0) | RA (r0));
tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4);
- tcg_out_mov (s, data_reg2, 0);
+ tcg_out_mov (s, TCG_TYPE_I32, data_reg2, 0);
}
else {
tcg_out32 (s, LWZ | RT (data_reg2) | RA (r0));
@@ -787,11 +787,11 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
/* slow path */
#if TARGET_LONG_BITS == 32
- tcg_out_mov (s, 3, addr_reg);
+ tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg);
ir = 4;
#else
- tcg_out_mov (s, 3, addr_reg2);
- tcg_out_mov (s, 4, addr_reg);
+ tcg_out_mov (s, TCG_TYPE_I32, 3, addr_reg2);
+ tcg_out_mov (s, TCG_TYPE_I32, 4, addr_reg);
#ifdef TCG_TARGET_CALL_ALIGN_ARGS
ir = 5;
#else
@@ -817,14 +817,14 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
| ME (31)));
break;
case 2:
- tcg_out_mov (s, ir, data_reg);
+ tcg_out_mov (s, TCG_TYPE_I32, ir, data_reg);
break;
case 3:
#ifdef TCG_TARGET_CALL_ALIGN_ARGS
ir = 5;
#endif
- tcg_out_mov (s, ir++, data_reg2);
- tcg_out_mov (s, ir, data_reg);
+ tcg_out_mov (s, TCG_TYPE_I32, ir++, data_reg2);
+ tcg_out_mov (s, TCG_TYPE_I32, ir, data_reg);
break;
}
ir++;
@@ -900,7 +900,7 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
#endif
}
-void tcg_target_qemu_prologue (TCGContext *s)
+static void tcg_target_qemu_prologue (TCGContext *s)
{
int i, frame_size;
@@ -1526,7 +1526,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
if (args[0] == args[2] || args[0] == args[3]) {
tcg_out32 (s, MULLW | TAB (0, args[2], args[3]));
tcg_out32 (s, MULHWU | TAB (args[1], args[2], args[3]));
- tcg_out_mov (s, args[0], 0);
+ tcg_out_mov (s, TCG_TYPE_I32, args[0], 0);
}
else {
tcg_out32 (s, MULLW | TAB (args[0], args[2], args[3]));
@@ -1584,7 +1584,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
case INDEX_op_rotr_i32:
if (const_args[2]) {
if (!args[2]) {
- tcg_out_mov (s, args[0], args[1]);
+ tcg_out_mov (s, TCG_TYPE_I32, args[0], args[1]);
}
else {
tcg_out32 (s, RLWINM
@@ -1612,7 +1612,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
if (args[0] == args[3] || args[0] == args[5]) {
tcg_out32 (s, ADDC | TAB (0, args[2], args[4]));
tcg_out32 (s, ADDE | TAB (args[1], args[3], args[5]));
- tcg_out_mov (s, args[0], 0);
+ tcg_out_mov (s, TCG_TYPE_I32, args[0], 0);
}
else {
tcg_out32 (s, ADDC | TAB (args[0], args[2], args[4]));
@@ -1623,7 +1623,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
if (args[0] == args[3] || args[0] == args[5]) {
tcg_out32 (s, SUBFC | TAB (0, args[4], args[2]));
tcg_out32 (s, SUBFE | TAB (args[1], args[5], args[3]));
- tcg_out_mov (s, args[0], 0);
+ tcg_out_mov (s, TCG_TYPE_I32, args[0], 0);
}
else {
tcg_out32 (s, SUBFC | TAB (args[0], args[4], args[2]));
@@ -1782,7 +1782,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
);
if (!a0) {
- tcg_out_mov (s, args[0], a0);
+ tcg_out_mov (s, TCG_TYPE_I32, args[0], a0);
}
}
break;
@@ -1885,7 +1885,7 @@ static const TCGTargetOpDef ppc_op_defs[] = {
{ -1 },
};
-void tcg_target_init(TCGContext *s)
+static void tcg_target_init(TCGContext *s)
{
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
tcg_regset_set32(tcg_target_call_clobber_regs, 0,
diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c
index 0b6c61f..0483d6b 100644
--- a/tcg/ppc64/tcg-target.c
+++ b/tcg/ppc64/tcg-target.c
@@ -435,7 +435,7 @@ static const uint32_t tcg_to_bc[10] = {
[TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE,
};
-static void tcg_out_mov (TCGContext *s, int ret, int arg)
+static void tcg_out_mov (TCGContext *s, TCGType type, int ret, int arg)
{
tcg_out32 (s, OR | SAB (arg, ret, arg));
}
@@ -644,7 +644,7 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
#endif
/* slow path */
- tcg_out_mov (s, 3, addr_reg);
+ tcg_out_mov (s, TCG_TYPE_I64, 3, addr_reg);
tcg_out_movi (s, TCG_TYPE_I64, 4, mem_index);
tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1);
@@ -664,7 +664,7 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
case 2:
case 3:
if (data_reg != 3)
- tcg_out_mov (s, data_reg, 3);
+ tcg_out_mov (s, TCG_TYPE_I64, data_reg, 3);
break;
}
label2_ptr = s->code_ptr;
@@ -746,7 +746,7 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc)
else tcg_out32 (s, LDX | TAB (data_reg, rbase, r0));
#else
if (bswap) {
- tcg_out_movi32 (s, 0, 4);
+ tcg_out_movi32 (s, TCG_TYPE_I64, 0, 4);
tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0));
tcg_out32 (s, LWBRX | RT ( r1) | RA (r0));
tcg_out_rld (s, RLDIMI, data_reg, r1, 32, 0);
@@ -790,7 +790,7 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
#endif
/* slow path */
- tcg_out_mov (s, 3, addr_reg);
+ tcg_out_mov (s, TCG_TYPE_I64, 3, addr_reg);
tcg_out_rld (s, RLDICL, 4, data_reg, 0, 64 - (1 << (3 + opc)));
tcg_out_movi (s, TCG_TYPE_I64, 5, mem_index);
@@ -860,7 +860,7 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc)
#endif
}
-void tcg_target_qemu_prologue (TCGContext *s)
+static void tcg_target_qemu_prologue (TCGContext *s)
{
int i, frame_size;
#ifndef __APPLE__
@@ -1663,7 +1663,7 @@ static const TCGTargetOpDef ppc_op_defs[] = {
{ -1 },
};
-void tcg_target_init (TCGContext *s)
+static void tcg_target_init (TCGContext *s)
{
tcg_regset_set32 (tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
tcg_regset_set32 (tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);
diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c
index 265194a..6f08aa4 100644
--- a/tcg/s390/tcg-target.c
+++ b/tcg/s390/tcg-target.c
@@ -84,17 +84,17 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
tcg_abort();
}
-void tcg_target_init(TCGContext *s)
+static void tcg_target_init(TCGContext *s)
{
/* gets called with KVM */
}
-void tcg_target_qemu_prologue(TCGContext *s)
+static void tcg_target_qemu_prologue(TCGContext *s)
{
/* gets called with KVM */
}
-static inline void tcg_out_mov(TCGContext *s, int ret, int arg)
+static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
{
tcg_abort();
}
diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h
index d8a2955..d7fe0c7 100644
--- a/tcg/s390/tcg-target.h
+++ b/tcg/s390/tcg-target.h
@@ -94,9 +94,4 @@ enum {
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
-#if QEMU_GNUC_PREREQ(4, 1)
- __builtin___clear_cache((char *) start, (char *) stop);
-#else
-#error not implemented
-#endif
}
diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c
index e460d44..5f1353a 100644
--- a/tcg/sparc/tcg-target.c
+++ b/tcg/sparc/tcg-target.c
@@ -304,7 +304,7 @@ static void tcg_out_arithc(TCGContext *s, int rd, int rs1,
| (val2const ? INSN_IMM13(val2) : INSN_RS2(val2)));
}
-static inline void tcg_out_mov(TCGContext *s, int ret, int arg)
+static inline void tcg_out_mov(TCGContext *s, TCGType type, int ret, int arg)
{
tcg_out_arith(s, ret, arg, TCG_REG_G0, ARITH_OR);
}
@@ -691,7 +691,7 @@ static void tcg_out_setcond2_i32(TCGContext *s, TCGCond cond, TCGArg ret,
#endif
/* Generate global QEMU prologue and epilogue code */
-void tcg_target_qemu_prologue(TCGContext *s)
+static void tcg_target_qemu_prologue(TCGContext *s)
{
tcg_out32(s, SAVE | INSN_RD(TCG_REG_O6) | INSN_RS1(TCG_REG_O6) |
INSN_IMM13(-TCG_TARGET_STACK_MINFRAME));
@@ -795,7 +795,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
tcg_out32(s, 0);
/* mov (delay slot) */
- tcg_out_mov(s, arg0, addr_reg);
+ tcg_out_mov(s, TCG_TYPE_PTR, arg0, addr_reg);
/* mov */
tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index);
@@ -845,7 +845,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
case 3:
default:
/* mov */
- tcg_out_mov(s, data_reg, arg0);
+ tcg_out_mov(s, TCG_TYPE_REG, data_reg, arg0);
break;
}
@@ -1007,10 +1007,10 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
tcg_out32(s, 0);
/* mov (delay slot) */
- tcg_out_mov(s, arg0, addr_reg);
+ tcg_out_mov(s, TCG_TYPE_PTR, arg0, addr_reg);
/* mov */
- tcg_out_mov(s, arg1, data_reg);
+ tcg_out_mov(s, TCG_TYPE_REG, arg1, data_reg);
/* mov */
tcg_out_movi(s, TCG_TYPE_I32, arg2, mem_index);
@@ -1533,7 +1533,7 @@ static const TCGTargetOpDef sparc_op_defs[] = {
{ -1 },
};
-void tcg_target_init(TCGContext *s)
+static void tcg_target_init(TCGContext *s)
{
tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
#if TCG_TARGET_REG_BITS == 64
diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h
index 674c73a..2a98fed 100644
--- a/tcg/tcg-opc.h
+++ b/tcg/tcg-opc.h
@@ -21,283 +21,284 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef DEF2
-#define DEF2(name, oargs, iargs, cargs, flags) DEF(name, oargs + iargs + cargs, 0)
-#endif
+
+/*
+ * DEF(name, oargs, iargs, cargs, flags)
+ */
/* predefined ops */
-DEF2(end, 0, 0, 0, 0) /* must be kept first */
-DEF2(nop, 0, 0, 0, 0)
-DEF2(nop1, 0, 0, 1, 0)
-DEF2(nop2, 0, 0, 2, 0)
-DEF2(nop3, 0, 0, 3, 0)
-DEF2(nopn, 0, 0, 1, 0) /* variable number of parameters */
+DEF(end, 0, 0, 0, 0) /* must be kept first */
+DEF(nop, 0, 0, 0, 0)
+DEF(nop1, 0, 0, 1, 0)
+DEF(nop2, 0, 0, 2, 0)
+DEF(nop3, 0, 0, 3, 0)
+DEF(nopn, 0, 0, 1, 0) /* variable number of parameters */
-DEF2(discard, 1, 0, 0, 0)
+DEF(discard, 1, 0, 0, 0)
-DEF2(set_label, 0, 0, 1, 0)
-DEF2(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */
-DEF2(jmp, 0, 1, 0, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
-DEF2(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF(set_label, 0, 0, 1, 0)
+DEF(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */
+DEF(jmp, 0, 1, 0, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
-DEF2(mov_i32, 1, 1, 0, 0)
-DEF2(movi_i32, 1, 0, 1, 0)
-DEF2(setcond_i32, 1, 2, 1, 0)
+DEF(mov_i32, 1, 1, 0, 0)
+DEF(movi_i32, 1, 0, 1, 0)
+DEF(setcond_i32, 1, 2, 1, 0)
/* load/store */
-DEF2(ld8u_i32, 1, 1, 1, 0)
-DEF2(ld8s_i32, 1, 1, 1, 0)
-DEF2(ld16u_i32, 1, 1, 1, 0)
-DEF2(ld16s_i32, 1, 1, 1, 0)
-DEF2(ld_i32, 1, 1, 1, 0)
-DEF2(st8_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
-DEF2(st16_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
-DEF2(st_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(ld8u_i32, 1, 1, 1, 0)
+DEF(ld8s_i32, 1, 1, 1, 0)
+DEF(ld16u_i32, 1, 1, 1, 0)
+DEF(ld16s_i32, 1, 1, 1, 0)
+DEF(ld_i32, 1, 1, 1, 0)
+DEF(st8_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st16_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st_i32, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
/* arith */
-DEF2(add_i32, 1, 2, 0, 0)
-DEF2(sub_i32, 1, 2, 0, 0)
-DEF2(mul_i32, 1, 2, 0, 0)
+DEF(add_i32, 1, 2, 0, 0)
+DEF(sub_i32, 1, 2, 0, 0)
+DEF(mul_i32, 1, 2, 0, 0)
#ifdef TCG_TARGET_HAS_div_i32
-DEF2(div_i32, 1, 2, 0, 0)
-DEF2(divu_i32, 1, 2, 0, 0)
-DEF2(rem_i32, 1, 2, 0, 0)
-DEF2(remu_i32, 1, 2, 0, 0)
+DEF(div_i32, 1, 2, 0, 0)
+DEF(divu_i32, 1, 2, 0, 0)
+DEF(rem_i32, 1, 2, 0, 0)
+DEF(remu_i32, 1, 2, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_div2_i32
-DEF2(div2_i32, 2, 3, 0, 0)
-DEF2(divu2_i32, 2, 3, 0, 0)
+DEF(div2_i32, 2, 3, 0, 0)
+DEF(divu2_i32, 2, 3, 0, 0)
#endif
-DEF2(and_i32, 1, 2, 0, 0)
-DEF2(or_i32, 1, 2, 0, 0)
-DEF2(xor_i32, 1, 2, 0, 0)
+DEF(and_i32, 1, 2, 0, 0)
+DEF(or_i32, 1, 2, 0, 0)
+DEF(xor_i32, 1, 2, 0, 0)
/* shifts/rotates */
-DEF2(shl_i32, 1, 2, 0, 0)
-DEF2(shr_i32, 1, 2, 0, 0)
-DEF2(sar_i32, 1, 2, 0, 0)
+DEF(shl_i32, 1, 2, 0, 0)
+DEF(shr_i32, 1, 2, 0, 0)
+DEF(sar_i32, 1, 2, 0, 0)
#ifdef TCG_TARGET_HAS_rot_i32
-DEF2(rotl_i32, 1, 2, 0, 0)
-DEF2(rotr_i32, 1, 2, 0, 0)
+DEF(rotl_i32, 1, 2, 0, 0)
+DEF(rotr_i32, 1, 2, 0, 0)
#endif
-DEF2(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
#if TCG_TARGET_REG_BITS == 32
-DEF2(add2_i32, 2, 4, 0, 0)
-DEF2(sub2_i32, 2, 4, 0, 0)
-DEF2(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
-DEF2(mulu2_i32, 2, 2, 0, 0)
-DEF2(setcond2_i32, 1, 4, 1, 0)
+DEF(add2_i32, 2, 4, 0, 0)
+DEF(sub2_i32, 2, 4, 0, 0)
+DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF(mulu2_i32, 2, 2, 0, 0)
+DEF(setcond2_i32, 1, 4, 1, 0)
#endif
#ifdef TCG_TARGET_HAS_ext8s_i32
-DEF2(ext8s_i32, 1, 1, 0, 0)
+DEF(ext8s_i32, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_ext16s_i32
-DEF2(ext16s_i32, 1, 1, 0, 0)
+DEF(ext16s_i32, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_ext8u_i32
-DEF2(ext8u_i32, 1, 1, 0, 0)
+DEF(ext8u_i32, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_ext16u_i32
-DEF2(ext16u_i32, 1, 1, 0, 0)
+DEF(ext16u_i32, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_bswap16_i32
-DEF2(bswap16_i32, 1, 1, 0, 0)
+DEF(bswap16_i32, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_bswap32_i32
-DEF2(bswap32_i32, 1, 1, 0, 0)
+DEF(bswap32_i32, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_not_i32
-DEF2(not_i32, 1, 1, 0, 0)
+DEF(not_i32, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_neg_i32
-DEF2(neg_i32, 1, 1, 0, 0)
+DEF(neg_i32, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_andc_i32
-DEF2(andc_i32, 1, 2, 0, 0)
+DEF(andc_i32, 1, 2, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_orc_i32
-DEF2(orc_i32, 1, 2, 0, 0)
+DEF(orc_i32, 1, 2, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_eqv_i32
-DEF2(eqv_i32, 1, 2, 0, 0)
+DEF(eqv_i32, 1, 2, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_nand_i32
-DEF2(nand_i32, 1, 2, 0, 0)
+DEF(nand_i32, 1, 2, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_nor_i32
-DEF2(nor_i32, 1, 2, 0, 0)
+DEF(nor_i32, 1, 2, 0, 0)
#endif
#if TCG_TARGET_REG_BITS == 64
-DEF2(mov_i64, 1, 1, 0, 0)
-DEF2(movi_i64, 1, 0, 1, 0)
-DEF2(setcond_i64, 1, 2, 1, 0)
+DEF(mov_i64, 1, 1, 0, 0)
+DEF(movi_i64, 1, 0, 1, 0)
+DEF(setcond_i64, 1, 2, 1, 0)
/* load/store */
-DEF2(ld8u_i64, 1, 1, 1, 0)
-DEF2(ld8s_i64, 1, 1, 1, 0)
-DEF2(ld16u_i64, 1, 1, 1, 0)
-DEF2(ld16s_i64, 1, 1, 1, 0)
-DEF2(ld32u_i64, 1, 1, 1, 0)
-DEF2(ld32s_i64, 1, 1, 1, 0)
-DEF2(ld_i64, 1, 1, 1, 0)
-DEF2(st8_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
-DEF2(st16_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
-DEF2(st32_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
-DEF2(st_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(ld8u_i64, 1, 1, 1, 0)
+DEF(ld8s_i64, 1, 1, 1, 0)
+DEF(ld16u_i64, 1, 1, 1, 0)
+DEF(ld16s_i64, 1, 1, 1, 0)
+DEF(ld32u_i64, 1, 1, 1, 0)
+DEF(ld32s_i64, 1, 1, 1, 0)
+DEF(ld_i64, 1, 1, 1, 0)
+DEF(st8_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st16_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st32_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
+DEF(st_i64, 0, 2, 1, TCG_OPF_SIDE_EFFECTS)
/* arith */
-DEF2(add_i64, 1, 2, 0, 0)
-DEF2(sub_i64, 1, 2, 0, 0)
-DEF2(mul_i64, 1, 2, 0, 0)
+DEF(add_i64, 1, 2, 0, 0)
+DEF(sub_i64, 1, 2, 0, 0)
+DEF(mul_i64, 1, 2, 0, 0)
#ifdef TCG_TARGET_HAS_div_i64
-DEF2(div_i64, 1, 2, 0, 0)
-DEF2(divu_i64, 1, 2, 0, 0)
-DEF2(rem_i64, 1, 2, 0, 0)
-DEF2(remu_i64, 1, 2, 0, 0)
+DEF(div_i64, 1, 2, 0, 0)
+DEF(divu_i64, 1, 2, 0, 0)
+DEF(rem_i64, 1, 2, 0, 0)
+DEF(remu_i64, 1, 2, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_div2_i64
-DEF2(div2_i64, 2, 3, 0, 0)
-DEF2(divu2_i64, 2, 3, 0, 0)
+DEF(div2_i64, 2, 3, 0, 0)
+DEF(divu2_i64, 2, 3, 0, 0)
#endif
-DEF2(and_i64, 1, 2, 0, 0)
-DEF2(or_i64, 1, 2, 0, 0)
-DEF2(xor_i64, 1, 2, 0, 0)
+DEF(and_i64, 1, 2, 0, 0)
+DEF(or_i64, 1, 2, 0, 0)
+DEF(xor_i64, 1, 2, 0, 0)
/* shifts/rotates */
-DEF2(shl_i64, 1, 2, 0, 0)
-DEF2(shr_i64, 1, 2, 0, 0)
-DEF2(sar_i64, 1, 2, 0, 0)
+DEF(shl_i64, 1, 2, 0, 0)
+DEF(shr_i64, 1, 2, 0, 0)
+DEF(sar_i64, 1, 2, 0, 0)
#ifdef TCG_TARGET_HAS_rot_i64
-DEF2(rotl_i64, 1, 2, 0, 0)
-DEF2(rotr_i64, 1, 2, 0, 0)
+DEF(rotl_i64, 1, 2, 0, 0)
+DEF(rotr_i64, 1, 2, 0, 0)
#endif
-DEF2(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
#ifdef TCG_TARGET_HAS_ext8s_i64
-DEF2(ext8s_i64, 1, 1, 0, 0)
+DEF(ext8s_i64, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_ext16s_i64
-DEF2(ext16s_i64, 1, 1, 0, 0)
+DEF(ext16s_i64, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_ext32s_i64
-DEF2(ext32s_i64, 1, 1, 0, 0)
+DEF(ext32s_i64, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_ext8u_i64
-DEF2(ext8u_i64, 1, 1, 0, 0)
+DEF(ext8u_i64, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_ext16u_i64
-DEF2(ext16u_i64, 1, 1, 0, 0)
+DEF(ext16u_i64, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_ext32u_i64
-DEF2(ext32u_i64, 1, 1, 0, 0)
+DEF(ext32u_i64, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_bswap16_i64
-DEF2(bswap16_i64, 1, 1, 0, 0)
+DEF(bswap16_i64, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_bswap32_i64
-DEF2(bswap32_i64, 1, 1, 0, 0)
+DEF(bswap32_i64, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_bswap64_i64
-DEF2(bswap64_i64, 1, 1, 0, 0)
+DEF(bswap64_i64, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_not_i64
-DEF2(not_i64, 1, 1, 0, 0)
+DEF(not_i64, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_neg_i64
-DEF2(neg_i64, 1, 1, 0, 0)
+DEF(neg_i64, 1, 1, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_andc_i64
-DEF2(andc_i64, 1, 2, 0, 0)
+DEF(andc_i64, 1, 2, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_orc_i64
-DEF2(orc_i64, 1, 2, 0, 0)
+DEF(orc_i64, 1, 2, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_eqv_i64
-DEF2(eqv_i64, 1, 2, 0, 0)
+DEF(eqv_i64, 1, 2, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_nand_i64
-DEF2(nand_i64, 1, 2, 0, 0)
+DEF(nand_i64, 1, 2, 0, 0)
#endif
#ifdef TCG_TARGET_HAS_nor_i64
-DEF2(nor_i64, 1, 2, 0, 0)
+DEF(nor_i64, 1, 2, 0, 0)
#endif
#endif
/* QEMU specific */
#if TARGET_LONG_BITS > TCG_TARGET_REG_BITS
-DEF2(debug_insn_start, 0, 0, 2, 0)
+DEF(debug_insn_start, 0, 0, 2, 0)
#else
-DEF2(debug_insn_start, 0, 0, 1, 0)
+DEF(debug_insn_start, 0, 0, 1, 0)
#endif
-DEF2(exit_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
-DEF2(goto_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF(exit_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
+DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS)
/* Note: even if TARGET_LONG_BITS is not defined, the INDEX_op
constants must be defined */
#if TCG_TARGET_REG_BITS == 32
#if TARGET_LONG_BITS == 32
-DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#else
-DEF2(qemu_ld8u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld8u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#endif
#if TARGET_LONG_BITS == 32
-DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#else
-DEF2(qemu_ld8s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld8s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#endif
#if TARGET_LONG_BITS == 32
-DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#else
-DEF2(qemu_ld16u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld16u, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#endif
#if TARGET_LONG_BITS == 32
-DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#else
-DEF2(qemu_ld16s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld16s, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#endif
#if TARGET_LONG_BITS == 32
-DEF2(qemu_ld32, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld32, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#else
-DEF2(qemu_ld32, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld32, 1, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#endif
#if TARGET_LONG_BITS == 32
-DEF2(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld64, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#else
-DEF2(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld64, 2, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#endif
#if TARGET_LONG_BITS == 32
-DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#else
-DEF2(qemu_st8, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st8, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#endif
#if TARGET_LONG_BITS == 32
-DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#else
-DEF2(qemu_st16, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st16, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#endif
#if TARGET_LONG_BITS == 32
-DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#else
-DEF2(qemu_st32, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st32, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#endif
#if TARGET_LONG_BITS == 32
-DEF2(qemu_st64, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st64, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#else
-DEF2(qemu_st64, 0, 4, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st64, 0, 4, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#endif
#else /* TCG_TARGET_REG_BITS == 32 */
-DEF2(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-DEF2(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-DEF2(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-DEF2(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-DEF2(qemu_ld32, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-DEF2(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-DEF2(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-DEF2(qemu_ld64, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld8u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld8s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld16u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld16s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld32, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld32u, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld32s, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_ld64, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-DEF2(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-DEF2(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-DEF2(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
-DEF2(qemu_st64, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st8, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st16, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st32, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
+DEF(qemu_st64, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS)
#endif /* TCG_TARGET_REG_BITS != 32 */
-#undef DEF2
+#undef DEF
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 880e7ce..3a18b76 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -63,15 +63,15 @@
#error GUEST_BASE not supported on this host.
#endif
+static void tcg_target_init(TCGContext *s);
+static void tcg_target_qemu_prologue(TCGContext *s);
static void patch_reloc(uint8_t *code_ptr, int type,
tcg_target_long value, tcg_target_long addend);
static TCGOpDef tcg_op_defs[] = {
-#define DEF(s, n, copy_size) { #s, 0, 0, n, n, 0, copy_size },
-#define DEF2(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags, 0 },
+#define DEF(s, oargs, iargs, cargs, flags) { #s, oargs, iargs, cargs, iargs + oargs + cargs, flags },
#include "tcg-opc.h"
#undef DEF
-#undef DEF2
};
static TCGRegSet tcg_target_available_regs[2];
@@ -1547,7 +1547,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
reg = tcg_reg_alloc(s, arg_ct->u.regs, s->reserved_regs);
}
if (ts->reg != reg) {
- tcg_out_mov(s, reg, ts->reg);
+ tcg_out_mov(s, ots->type, reg, ts->reg);
}
}
} else if (ts->val_type == TEMP_VAL_MEM) {
@@ -1652,7 +1652,7 @@ static void tcg_reg_alloc_op(TCGContext *s,
/* allocate a new register matching the constraint
and move the temporary register into it */
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
- tcg_out_mov(s, reg, ts->reg);
+ tcg_out_mov(s, ts->type, reg, ts->reg);
}
new_args[i] = reg;
const_args[i] = 0;
@@ -1734,7 +1734,7 @@ static void tcg_reg_alloc_op(TCGContext *s,
ts = &s->temps[args[i]];
reg = new_args[i];
if (ts->fixed_reg && ts->reg != reg) {
- tcg_out_mov(s, ts->reg, reg);
+ tcg_out_mov(s, ts->type, ts->reg, reg);
}
}
}
@@ -1820,7 +1820,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
tcg_reg_free(s, reg);
if (ts->val_type == TEMP_VAL_REG) {
if (ts->reg != reg) {
- tcg_out_mov(s, reg, ts->reg);
+ tcg_out_mov(s, ts->type, reg, ts->reg);
}
} else if (ts->val_type == TEMP_VAL_MEM) {
tcg_out_ld(s, ts->type, reg, ts->mem_reg, ts->mem_offset);
@@ -1849,7 +1849,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
reg = ts->reg;
if (!tcg_regset_test_reg(arg_ct->u.regs, reg)) {
reg = tcg_reg_alloc(s, arg_ct->u.regs, allocated_regs);
- tcg_out_mov(s, reg, ts->reg);
+ tcg_out_mov(s, ts->type, reg, ts->reg);
}
func_arg = reg;
tcg_regset_set_reg(allocated_regs, reg);
@@ -1908,7 +1908,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
assert(s->reg_to_temp[reg] == -1);
if (ts->fixed_reg) {
if (ts->reg != reg) {
- tcg_out_mov(s, ts->reg, reg);
+ tcg_out_mov(s, ts->type, ts->reg, reg);
}
} else {
if (ts->val_type == TEMP_VAL_REG)
diff --git a/tcg/tcg.h b/tcg/tcg.h
index 5853823..972df72 100644
--- a/tcg/tcg.h
+++ b/tcg/tcg.h
@@ -48,7 +48,7 @@ typedef uint64_t TCGRegSet;
#endif
typedef enum TCGOpcode {
-#define DEF(s, n, copy_size) INDEX_op_ ## s,
+#define DEF(name, oargs, iargs, cargs, flags) INDEX_op_ ## name,
#include "tcg-opc.h"
#undef DEF
NB_OPS,
@@ -101,11 +101,18 @@ typedef enum TCGType {
TCG_TYPE_I64,
TCG_TYPE_COUNT, /* number of different types */
+ /* An alias for the size of the host register. */
#if TCG_TARGET_REG_BITS == 32
- TCG_TYPE_PTR = TCG_TYPE_I32,
+ TCG_TYPE_REG = TCG_TYPE_I32,
#else
- TCG_TYPE_PTR = TCG_TYPE_I64,
+ TCG_TYPE_REG = TCG_TYPE_I64,
#endif
+
+ /* An alias for the size of the native pointer. We don't currently
+ support any hosts with 64-bit registers and 32-bit pointers. */
+ TCG_TYPE_PTR = TCG_TYPE_REG,
+
+ /* An alias for the size of the target "long", aka register. */
#if TARGET_LONG_BITS == 64
TCG_TYPE_TL = TCG_TYPE_I64,
#else
@@ -415,7 +422,6 @@ typedef struct TCGOpDef {
const char *name;
uint8_t nb_oargs, nb_iargs, nb_cargs, nb_args;
uint8_t flags;
- uint16_t copy_size;
TCGArgConstraint *args_ct;
int *sorted_args;
#if defined(CONFIG_DEBUG_TCG)
@@ -428,9 +434,6 @@ typedef struct TCGTargetOpDef {
const char *args_ct_str[TCG_MAX_OP_ARGS];
} TCGTargetOpDef;
-void tcg_target_init(TCGContext *s);
-void tcg_target_qemu_prologue(TCGContext *s);
-
#define tcg_abort() \
do {\
fprintf(stderr, "%s:%d: tcg fatal error\n", __FILE__, __LINE__);\
diff --git a/tcg/x86_64/tcg-target.c b/tcg/x86_64/tcg-target.c
deleted file mode 100644
index 3892f75..0000000
--- a/tcg/x86_64/tcg-target.c
+++ /dev/null
@@ -1,1454 +0,0 @@
-/*
- * Tiny Code Generator for QEMU
- *
- * Copyright (c) 2008 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef NDEBUG
-static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
- "%rax",
- "%rcx",
- "%rdx",
- "%rbx",
- "%rsp",
- "%rbp",
- "%rsi",
- "%rdi",
- "%r8",
- "%r9",
- "%r10",
- "%r11",
- "%r12",
- "%r13",
- "%r14",
- "%r15",
-};
-#endif
-
-static const int tcg_target_reg_alloc_order[] = {
- TCG_REG_RBP,
- TCG_REG_RBX,
- TCG_REG_R12,
- TCG_REG_R13,
- TCG_REG_R14,
- TCG_REG_R15,
- TCG_REG_R10,
- TCG_REG_R11,
- TCG_REG_R9,
- TCG_REG_R8,
- TCG_REG_RCX,
- TCG_REG_RDX,
- TCG_REG_RSI,
- TCG_REG_RDI,
- TCG_REG_RAX,
-};
-
-static const int tcg_target_call_iarg_regs[6] = {
- TCG_REG_RDI,
- TCG_REG_RSI,
- TCG_REG_RDX,
- TCG_REG_RCX,
- TCG_REG_R8,
- TCG_REG_R9,
-};
-
-static const int tcg_target_call_oarg_regs[2] = {
- TCG_REG_RAX,
- TCG_REG_RDX
-};
-
-static uint8_t *tb_ret_addr;
-
-static void patch_reloc(uint8_t *code_ptr, int type,
- tcg_target_long value, tcg_target_long addend)
-{
- value += addend;
- switch(type) {
- case R_X86_64_32:
- if (value != (uint32_t)value)
- tcg_abort();
- *(uint32_t *)code_ptr = value;
- break;
- case R_X86_64_32S:
- if (value != (int32_t)value)
- tcg_abort();
- *(uint32_t *)code_ptr = value;
- break;
- case R_386_PC32:
- value -= (long)code_ptr;
- if (value != (int32_t)value)
- tcg_abort();
- *(uint32_t *)code_ptr = value;
- break;
- default:
- tcg_abort();
- }
-}
-
-/* maximum number of register used for input function arguments */
-static inline int tcg_target_get_call_iarg_regs_count(int flags)
-{
- return 6;
-}
-
-/* parse target specific constraints */
-static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
-{
- const char *ct_str;
-
- ct_str = *pct_str;
- switch(ct_str[0]) {
- case 'a':
- ct->ct |= TCG_CT_REG;
- tcg_regset_set_reg(ct->u.regs, TCG_REG_RAX);
- break;
- case 'b':
- ct->ct |= TCG_CT_REG;
- tcg_regset_set_reg(ct->u.regs, TCG_REG_RBX);
- break;
- case 'c':
- ct->ct |= TCG_CT_REG;
- tcg_regset_set_reg(ct->u.regs, TCG_REG_RCX);
- break;
- case 'd':
- ct->ct |= TCG_CT_REG;
- tcg_regset_set_reg(ct->u.regs, TCG_REG_RDX);
- break;
- case 'S':
- ct->ct |= TCG_CT_REG;
- tcg_regset_set_reg(ct->u.regs, TCG_REG_RSI);
- break;
- case 'D':
- ct->ct |= TCG_CT_REG;
- tcg_regset_set_reg(ct->u.regs, TCG_REG_RDI);
- break;
- case 'q':
- ct->ct |= TCG_CT_REG;
- tcg_regset_set32(ct->u.regs, 0, 0xf);
- break;
- case 'r':
- ct->ct |= TCG_CT_REG;
- tcg_regset_set32(ct->u.regs, 0, 0xffff);
- break;
- case 'L': /* qemu_ld/st constraint */
- ct->ct |= TCG_CT_REG;
- tcg_regset_set32(ct->u.regs, 0, 0xffff);
- tcg_regset_reset_reg(ct->u.regs, TCG_REG_RSI);
- tcg_regset_reset_reg(ct->u.regs, TCG_REG_RDI);
- break;
- case 'e':
- ct->ct |= TCG_CT_CONST_S32;
- break;
- case 'Z':
- ct->ct |= TCG_CT_CONST_U32;
- break;
- default:
- return -1;
- }
- ct_str++;
- *pct_str = ct_str;
- return 0;
-}
-
-/* test if a constant matches the constraint */
-static inline int tcg_target_const_match(tcg_target_long val,
- const TCGArgConstraint *arg_ct)
-{
- int ct;
- ct = arg_ct->ct;
- if (ct & TCG_CT_CONST)
- return 1;
- else if ((ct & TCG_CT_CONST_S32) && val == (int32_t)val)
- return 1;
- else if ((ct & TCG_CT_CONST_U32) && val == (uint32_t)val)
- return 1;
- else
- return 0;
-}
-
-#define ARITH_ADD 0
-#define ARITH_OR 1
-#define ARITH_ADC 2
-#define ARITH_SBB 3
-#define ARITH_AND 4
-#define ARITH_SUB 5
-#define ARITH_XOR 6
-#define ARITH_CMP 7
-
-#define SHIFT_ROL 0
-#define SHIFT_ROR 1
-#define SHIFT_SHL 4
-#define SHIFT_SHR 5
-#define SHIFT_SAR 7
-
-#define JCC_JMP (-1)
-#define JCC_JO 0x0
-#define JCC_JNO 0x1
-#define JCC_JB 0x2
-#define JCC_JAE 0x3
-#define JCC_JE 0x4
-#define JCC_JNE 0x5
-#define JCC_JBE 0x6
-#define JCC_JA 0x7
-#define JCC_JS 0x8
-#define JCC_JNS 0x9
-#define JCC_JP 0xa
-#define JCC_JNP 0xb
-#define JCC_JL 0xc
-#define JCC_JGE 0xd
-#define JCC_JLE 0xe
-#define JCC_JG 0xf
-
-#define P_EXT 0x100 /* 0x0f opcode prefix */
-#define P_REXW 0x200 /* set rex.w = 1 */
-#define P_REXB_R 0x400 /* REG field as byte register */
-#define P_REXB_RM 0x800 /* R/M field as byte register */
-
-static const uint8_t tcg_cond_to_jcc[10] = {
- [TCG_COND_EQ] = JCC_JE,
- [TCG_COND_NE] = JCC_JNE,
- [TCG_COND_LT] = JCC_JL,
- [TCG_COND_GE] = JCC_JGE,
- [TCG_COND_LE] = JCC_JLE,
- [TCG_COND_GT] = JCC_JG,
- [TCG_COND_LTU] = JCC_JB,
- [TCG_COND_GEU] = JCC_JAE,
- [TCG_COND_LEU] = JCC_JBE,
- [TCG_COND_GTU] = JCC_JA,
-};
-
-static void tcg_out_opc(TCGContext *s, int opc, int r, int rm, int x)
-{
- int rex = 0;
-
- rex |= (opc & P_REXW) >> 6; /* REX.W */
- rex |= (r & 8) >> 1; /* REX.R */
- rex |= (x & 8) >> 2; /* REX.X */
- rex |= (rm & 8) >> 3; /* REX.B */
-
- /* P_REXB_{R,RM} indicates that the given register is the low byte.
- For %[abcd]l we need no REX prefix, but for %{si,di,bp,sp}l we do,
- as otherwise the encoding indicates %[abcd]h. Note that the values
- that are ORed in merely indicate that the REX byte must be present;
- those bits get discarded in output. */
- rex |= opc & (r >= 4 ? P_REXB_R : 0);
- rex |= opc & (rm >= 4 ? P_REXB_RM : 0);
-
- if (rex) {
- tcg_out8(s, (uint8_t)(rex | 0x40));
- }
- if (opc & P_EXT) {
- tcg_out8(s, 0x0f);
- }
- tcg_out8(s, opc & 0xff);
-}
-
-static inline void tcg_out_modrm(TCGContext *s, int opc, int r, int rm)
-{
- tcg_out_opc(s, opc, r, rm, 0);
- tcg_out8(s, 0xc0 | ((r & 7) << 3) | (rm & 7));
-}
-
-/* rm < 0 means no register index plus (-rm - 1 immediate bytes) */
-static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r, int rm,
- tcg_target_long offset)
-{
- if (rm < 0) {
- tcg_target_long val;
- tcg_out_opc(s, opc, r, 0, 0);
- val = offset - ((tcg_target_long)s->code_ptr + 5 + (-rm - 1));
- if (val == (int32_t)val) {
- /* eip relative */
- tcg_out8(s, 0x05 | ((r & 7) << 3));
- tcg_out32(s, val);
- } else if (offset == (int32_t)offset) {
- tcg_out8(s, 0x04 | ((r & 7) << 3));
- tcg_out8(s, 0x25); /* sib */
- tcg_out32(s, offset);
- } else {
- tcg_abort();
- }
- } else if (offset == 0 && (rm & 7) != TCG_REG_RBP) {
- tcg_out_opc(s, opc, r, rm, 0);
- if ((rm & 7) == TCG_REG_RSP) {
- tcg_out8(s, 0x04 | ((r & 7) << 3));
- tcg_out8(s, 0x24);
- } else {
- tcg_out8(s, 0x00 | ((r & 7) << 3) | (rm & 7));
- }
- } else if ((int8_t)offset == offset) {
- tcg_out_opc(s, opc, r, rm, 0);
- if ((rm & 7) == TCG_REG_RSP) {
- tcg_out8(s, 0x44 | ((r & 7) << 3));
- tcg_out8(s, 0x24);
- } else {
- tcg_out8(s, 0x40 | ((r & 7) << 3) | (rm & 7));
- }
- tcg_out8(s, offset);
- } else {
- tcg_out_opc(s, opc, r, rm, 0);
- if ((rm & 7) == TCG_REG_RSP) {
- tcg_out8(s, 0x84 | ((r & 7) << 3));
- tcg_out8(s, 0x24);
- } else {
- tcg_out8(s, 0x80 | ((r & 7) << 3) | (rm & 7));
- }
- tcg_out32(s, offset);
- }
-}
-
-#if defined(CONFIG_SOFTMMU)
-/* XXX: incomplete. index must be different from ESP */
-static void tcg_out_modrm_offset2(TCGContext *s, int opc, int r, int rm,
- int index, int shift,
- tcg_target_long offset)
-{
- int mod;
- if (rm == -1)
- tcg_abort();
- if (offset == 0 && (rm & 7) != TCG_REG_RBP) {
- mod = 0;
- } else if (offset == (int8_t)offset) {
- mod = 0x40;
- } else if (offset == (int32_t)offset) {
- mod = 0x80;
- } else {
- tcg_abort();
- }
- if (index == -1) {
- tcg_out_opc(s, opc, r, rm, 0);
- if ((rm & 7) == TCG_REG_RSP) {
- tcg_out8(s, mod | ((r & 7) << 3) | 0x04);
- tcg_out8(s, 0x04 | (rm & 7));
- } else {
- tcg_out8(s, mod | ((r & 7) << 3) | (rm & 7));
- }
- } else {
- tcg_out_opc(s, opc, r, rm, index);
- tcg_out8(s, mod | ((r & 7) << 3) | 0x04);
- tcg_out8(s, (shift << 6) | ((index & 7) << 3) | (rm & 7));
- }
- if (mod == 0x40) {
- tcg_out8(s, offset);
- } else if (mod == 0x80) {
- tcg_out32(s, offset);
- }
-}
-#endif
-
-static inline void tcg_out_mov(TCGContext *s, int ret, int arg)
-{
- tcg_out_modrm(s, 0x8b | P_REXW, ret, arg);
-}
-
-static inline void tcg_out_movi(TCGContext *s, TCGType type,
- int ret, tcg_target_long arg)
-{
- if (arg == 0) {
- tcg_out_modrm(s, 0x01 | (ARITH_XOR << 3), ret, ret); /* xor r0,r0 */
- } else if (arg == (uint32_t)arg || type == TCG_TYPE_I32) {
- tcg_out_opc(s, 0xb8 + (ret & 7), 0, ret, 0);
- tcg_out32(s, arg);
- } else if (arg == (int32_t)arg) {
- tcg_out_modrm(s, 0xc7 | P_REXW, 0, ret);
- tcg_out32(s, arg);
- } else {
- tcg_out_opc(s, (0xb8 + (ret & 7)) | P_REXW, 0, ret, 0);
- tcg_out32(s, arg);
- tcg_out32(s, arg >> 32);
- }
-}
-
-static void tcg_out_goto(TCGContext *s, int call, uint8_t *target)
-{
- int32_t disp;
-
- disp = target - s->code_ptr - 5;
- if (disp == (target - s->code_ptr - 5)) {
- tcg_out8(s, call ? 0xe8 : 0xe9);
- tcg_out32(s, disp);
- } else {
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R10, (tcg_target_long) target);
- tcg_out_modrm(s, 0xff, call ? 2 : 4, TCG_REG_R10);
- }
-}
-
-static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
- int arg1, tcg_target_long arg2)
-{
- if (type == TCG_TYPE_I32)
- tcg_out_modrm_offset(s, 0x8b, ret, arg1, arg2); /* movl */
- else
- tcg_out_modrm_offset(s, 0x8b | P_REXW, ret, arg1, arg2); /* movq */
-}
-
-static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
- int arg1, tcg_target_long arg2)
-{
- if (type == TCG_TYPE_I32)
- tcg_out_modrm_offset(s, 0x89, arg, arg1, arg2); /* movl */
- else
- tcg_out_modrm_offset(s, 0x89 | P_REXW, arg, arg1, arg2); /* movq */
-}
-
-static inline void tgen_arithi32(TCGContext *s, int c, int r0, int32_t val)
-{
- if ((c == ARITH_ADD && val == 1) || (c == ARITH_SUB && val == -1)) {
- /* inc */
- tcg_out_modrm(s, 0xff, 0, r0);
- } else if ((c == ARITH_ADD && val == -1) || (c == ARITH_SUB && val == 1)) {
- /* dec */
- tcg_out_modrm(s, 0xff, 1, r0);
- } else if (val == (int8_t)val) {
- tcg_out_modrm(s, 0x83, c, r0);
- tcg_out8(s, val);
- } else if (c == ARITH_AND && val == 0xffu) {
- /* movzbl */
- tcg_out_modrm(s, 0xb6 | P_EXT | P_REXB_RM, r0, r0);
- } else if (c == ARITH_AND && val == 0xffffu) {
- /* movzwl */
- tcg_out_modrm(s, 0xb7 | P_EXT, r0, r0);
- } else {
- tcg_out_modrm(s, 0x81, c, r0);
- tcg_out32(s, val);
- }
-}
-
-static inline void tgen_arithi64(TCGContext *s, int c, int r0, int64_t val)
-{
- if ((c == ARITH_ADD && val == 1) || (c == ARITH_SUB && val == -1)) {
- /* inc */
- tcg_out_modrm(s, 0xff | P_REXW, 0, r0);
- } else if ((c == ARITH_ADD && val == -1) || (c == ARITH_SUB && val == 1)) {
- /* dec */
- tcg_out_modrm(s, 0xff | P_REXW, 1, r0);
- } else if (c == ARITH_AND && val == 0xffffffffu) {
- /* 32-bit mov zero extends */
- tcg_out_modrm(s, 0x8b, r0, r0);
- } else if (c == ARITH_AND && val == (uint32_t)val) {
- /* AND with no high bits set can use a 32-bit operation. */
- tgen_arithi32(s, c, r0, (uint32_t)val);
- } else if (val == (int8_t)val) {
- tcg_out_modrm(s, 0x83 | P_REXW, c, r0);
- tcg_out8(s, val);
- } else if (val == (int32_t)val) {
- tcg_out_modrm(s, 0x81 | P_REXW, c, r0);
- tcg_out32(s, val);
- } else {
- tcg_abort();
- }
-}
-
-static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
-{
- if (val != 0)
- tgen_arithi64(s, ARITH_ADD, reg, val);
-}
-
-static void tcg_out_jxx(TCGContext *s, int opc, int label_index)
-{
- int32_t val, val1;
- TCGLabel *l = &s->labels[label_index];
-
- if (l->has_value) {
- val = l->u.value - (tcg_target_long)s->code_ptr;
- val1 = val - 2;
- if ((int8_t)val1 == val1) {
- if (opc == -1)
- tcg_out8(s, 0xeb);
- else
- tcg_out8(s, 0x70 + opc);
- tcg_out8(s, val1);
- } else {
- if (opc == -1) {
- tcg_out8(s, 0xe9);
- tcg_out32(s, val - 5);
- } else {
- tcg_out8(s, 0x0f);
- tcg_out8(s, 0x80 + opc);
- tcg_out32(s, val - 6);
- }
- }
- } else {
- if (opc == -1) {
- tcg_out8(s, 0xe9);
- } else {
- tcg_out8(s, 0x0f);
- tcg_out8(s, 0x80 + opc);
- }
- tcg_out_reloc(s, s->code_ptr, R_386_PC32, label_index, -4);
- s->code_ptr += 4;
- }
-}
-
-static void tcg_out_cmp(TCGContext *s, TCGArg arg1, TCGArg arg2,
- int const_arg2, int rexw)
-{
- if (const_arg2) {
- if (arg2 == 0) {
- /* test r, r */
- tcg_out_modrm(s, 0x85 | rexw, arg1, arg1);
- } else {
- if (rexw) {
- tgen_arithi64(s, ARITH_CMP, arg1, arg2);
- } else {
- tgen_arithi32(s, ARITH_CMP, arg1, arg2);
- }
- }
- } else {
- tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3) | rexw, arg2, arg1);
- }
-}
-
-static void tcg_out_brcond(TCGContext *s, TCGCond cond,
- TCGArg arg1, TCGArg arg2, int const_arg2,
- int label_index, int rexw)
-{
- tcg_out_cmp(s, arg1, arg2, const_arg2, rexw);
- tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index);
-}
-
-static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGArg dest,
- TCGArg arg1, TCGArg arg2, int const_arg2, int rexw)
-{
- tcg_out_cmp(s, arg1, arg2, const_arg2, rexw);
- /* setcc */
- tcg_out_modrm(s, 0x90 | tcg_cond_to_jcc[cond] | P_EXT | P_REXB_RM, 0, dest);
- tgen_arithi32(s, ARITH_AND, dest, 0xff);
-}
-
-#if defined(CONFIG_SOFTMMU)
-
-#include "../../softmmu_defs.h"
-
-static void *qemu_ld_helpers[4] = {
- __ldb_mmu,
- __ldw_mmu,
- __ldl_mmu,
- __ldq_mmu,
-};
-
-static void *qemu_st_helpers[4] = {
- __stb_mmu,
- __stw_mmu,
- __stl_mmu,
- __stq_mmu,
-};
-#endif
-
-static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
- int opc)
-{
- int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw;
- int32_t offset;
-#if defined(CONFIG_SOFTMMU)
- uint8_t *label1_ptr, *label2_ptr;
-#endif
-
- data_reg = *args++;
- addr_reg = *args++;
- mem_index = *args;
- s_bits = opc & 3;
-
- r0 = TCG_REG_RDI;
- r1 = TCG_REG_RSI;
-
-#if TARGET_LONG_BITS == 32
- rexw = 0;
-#else
- rexw = P_REXW;
-#endif
-#if defined(CONFIG_SOFTMMU)
- /* mov */
- tcg_out_modrm(s, 0x8b | rexw, r1, addr_reg);
-
- /* mov */
- tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg);
-
- tcg_out_modrm(s, 0xc1 | rexw, 5, r1); /* shr $x, r1 */
- tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
-
- tcg_out_modrm(s, 0x81 | rexw, 4, r0); /* andl $x, r0 */
- tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
-
- tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */
- tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
-
- /* lea offset(r1, env), r1 */
- tcg_out_modrm_offset2(s, 0x8d | P_REXW, r1, r1, TCG_AREG0, 0,
- offsetof(CPUState, tlb_table[mem_index][0].addr_read));
-
- /* cmp 0(r1), r0 */
- tcg_out_modrm_offset(s, 0x3b | rexw, r0, r1, 0);
-
- /* mov */
- tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg);
-
- /* je label1 */
- tcg_out8(s, 0x70 + JCC_JE);
- label1_ptr = s->code_ptr;
- s->code_ptr++;
-
- /* XXX: move that code at the end of the TB */
- tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RSI, mem_index);
- tcg_out_goto(s, 1, qemu_ld_helpers[s_bits]);
-
- switch(opc) {
- case 0 | 4:
- /* movsbq */
- tcg_out_modrm(s, 0xbe | P_EXT | P_REXW, data_reg, TCG_REG_RAX);
- break;
- case 1 | 4:
- /* movswq */
- tcg_out_modrm(s, 0xbf | P_EXT | P_REXW, data_reg, TCG_REG_RAX);
- break;
- case 2 | 4:
- /* movslq */
- tcg_out_modrm(s, 0x63 | P_REXW, data_reg, TCG_REG_RAX);
- break;
- case 0:
- /* movzbq */
- tcg_out_modrm(s, 0xb6 | P_EXT | P_REXW, data_reg, TCG_REG_RAX);
- break;
- case 1:
- /* movzwq */
- tcg_out_modrm(s, 0xb7 | P_EXT | P_REXW, data_reg, TCG_REG_RAX);
- break;
- case 2:
- default:
- /* movl */
- tcg_out_modrm(s, 0x8b, data_reg, TCG_REG_RAX);
- break;
- case 3:
- tcg_out_mov(s, data_reg, TCG_REG_RAX);
- break;
- }
-
- /* jmp label2 */
- tcg_out8(s, 0xeb);
- label2_ptr = s->code_ptr;
- s->code_ptr++;
-
- /* label1: */
- *label1_ptr = s->code_ptr - label1_ptr - 1;
-
- /* add x(r1), r0 */
- tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) -
- offsetof(CPUTLBEntry, addr_read));
- offset = 0;
-#else
- if (GUEST_BASE == (int32_t)GUEST_BASE) {
- r0 = addr_reg;
- offset = GUEST_BASE;
- } else {
- offset = 0;
- /* movq $GUEST_BASE, r0 */
- tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0);
- tcg_out32(s, GUEST_BASE);
- tcg_out32(s, GUEST_BASE >> 32);
- /* addq addr_reg, r0 */
- tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0);
- }
-#endif
-
-#ifdef TARGET_WORDS_BIGENDIAN
- bswap = 1;
-#else
- bswap = 0;
-#endif
- switch(opc) {
- case 0:
- /* movzbl */
- tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, offset);
- break;
- case 0 | 4:
- /* movsbX */
- tcg_out_modrm_offset(s, 0xbe | P_EXT | rexw, data_reg, r0, offset);
- break;
- case 1:
- /* movzwl */
- tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, offset);
- if (bswap) {
- /* rolw $8, data_reg */
- tcg_out8(s, 0x66);
- tcg_out_modrm(s, 0xc1, 0, data_reg);
- tcg_out8(s, 8);
- }
- break;
- case 1 | 4:
- if (bswap) {
- /* movzwl */
- tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, offset);
- /* rolw $8, data_reg */
- tcg_out8(s, 0x66);
- tcg_out_modrm(s, 0xc1, 0, data_reg);
- tcg_out8(s, 8);
-
- /* movswX data_reg, data_reg */
- tcg_out_modrm(s, 0xbf | P_EXT | rexw, data_reg, data_reg);
- } else {
- /* movswX */
- tcg_out_modrm_offset(s, 0xbf | P_EXT | rexw, data_reg, r0, offset);
- }
- break;
- case 2:
- /* movl (r0), data_reg */
- tcg_out_modrm_offset(s, 0x8b, data_reg, r0, offset);
- if (bswap) {
- /* bswap */
- tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0);
- }
- break;
- case 2 | 4:
- if (bswap) {
- /* movl (r0), data_reg */
- tcg_out_modrm_offset(s, 0x8b, data_reg, r0, offset);
- /* bswap */
- tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT, 0, data_reg, 0);
- /* movslq */
- tcg_out_modrm(s, 0x63 | P_REXW, data_reg, data_reg);
- } else {
- /* movslq */
- tcg_out_modrm_offset(s, 0x63 | P_REXW, data_reg, r0, offset);
- }
- break;
- case 3:
- /* movq (r0), data_reg */
- tcg_out_modrm_offset(s, 0x8b | P_REXW, data_reg, r0, offset);
- if (bswap) {
- /* bswap */
- tcg_out_opc(s, (0xc8 + (data_reg & 7)) | P_EXT | P_REXW, 0, data_reg, 0);
- }
- break;
- default:
- tcg_abort();
- }
-
-#if defined(CONFIG_SOFTMMU)
- /* label2: */
- *label2_ptr = s->code_ptr - label2_ptr - 1;
-#endif
-}
-
-static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
- int opc)
-{
- int addr_reg, data_reg, r0, r1, mem_index, s_bits, bswap, rexw;
- int32_t offset;
-#if defined(CONFIG_SOFTMMU)
- uint8_t *label1_ptr, *label2_ptr;
-#endif
-
- data_reg = *args++;
- addr_reg = *args++;
- mem_index = *args;
-
- s_bits = opc;
-
- r0 = TCG_REG_RDI;
- r1 = TCG_REG_RSI;
-
-#if TARGET_LONG_BITS == 32
- rexw = 0;
-#else
- rexw = P_REXW;
-#endif
-#if defined(CONFIG_SOFTMMU)
- /* mov */
- tcg_out_modrm(s, 0x8b | rexw, r1, addr_reg);
-
- /* mov */
- tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg);
-
- tcg_out_modrm(s, 0xc1 | rexw, 5, r1); /* shr $x, r1 */
- tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
-
- tcg_out_modrm(s, 0x81 | rexw, 4, r0); /* andl $x, r0 */
- tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
-
- tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */
- tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
-
- /* lea offset(r1, env), r1 */
- tcg_out_modrm_offset2(s, 0x8d | P_REXW, r1, r1, TCG_AREG0, 0,
- offsetof(CPUState, tlb_table[mem_index][0].addr_write));
-
- /* cmp 0(r1), r0 */
- tcg_out_modrm_offset(s, 0x3b | rexw, r0, r1, 0);
-
- /* mov */
- tcg_out_modrm(s, 0x8b | rexw, r0, addr_reg);
-
- /* je label1 */
- tcg_out8(s, 0x70 + JCC_JE);
- label1_ptr = s->code_ptr;
- s->code_ptr++;
-
- /* XXX: move that code at the end of the TB */
- switch(opc) {
- case 0:
- /* movzbl */
- tcg_out_modrm(s, 0xb6 | P_EXT | P_REXB_RM, TCG_REG_RSI, data_reg);
- break;
- case 1:
- /* movzwl */
- tcg_out_modrm(s, 0xb7 | P_EXT, TCG_REG_RSI, data_reg);
- break;
- case 2:
- /* movl */
- tcg_out_modrm(s, 0x8b, TCG_REG_RSI, data_reg);
- break;
- default:
- case 3:
- tcg_out_mov(s, TCG_REG_RSI, data_reg);
- break;
- }
- tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_RDX, mem_index);
- tcg_out_goto(s, 1, qemu_st_helpers[s_bits]);
-
- /* jmp label2 */
- tcg_out8(s, 0xeb);
- label2_ptr = s->code_ptr;
- s->code_ptr++;
-
- /* label1: */
- *label1_ptr = s->code_ptr - label1_ptr - 1;
-
- /* add x(r1), r0 */
- tcg_out_modrm_offset(s, 0x03 | P_REXW, r0, r1, offsetof(CPUTLBEntry, addend) -
- offsetof(CPUTLBEntry, addr_write));
- offset = 0;
-#else
- if (GUEST_BASE == (int32_t)GUEST_BASE) {
- r0 = addr_reg;
- offset = GUEST_BASE;
- } else {
- offset = 0;
- /* movq $GUEST_BASE, r0 */
- tcg_out_opc(s, (0xb8 + (r0 & 7)) | P_REXW, 0, r0, 0);
- tcg_out32(s, GUEST_BASE);
- tcg_out32(s, GUEST_BASE >> 32);
- /* addq addr_reg, r0 */
- tcg_out_modrm(s, 0x01 | P_REXW, addr_reg, r0);
- }
-#endif
-
-#ifdef TARGET_WORDS_BIGENDIAN
- bswap = 1;
-#else
- bswap = 0;
-#endif
- switch(opc) {
- case 0:
- /* movb */
- tcg_out_modrm_offset(s, 0x88 | P_REXB_R, data_reg, r0, offset);
- break;
- case 1:
- if (bswap) {
- tcg_out_modrm(s, 0x8b, r1, data_reg); /* movl */
- tcg_out8(s, 0x66); /* rolw $8, %ecx */
- tcg_out_modrm(s, 0xc1, 0, r1);
- tcg_out8(s, 8);
- data_reg = r1;
- }
- /* movw */
- tcg_out8(s, 0x66);
- tcg_out_modrm_offset(s, 0x89, data_reg, r0, offset);
- break;
- case 2:
- if (bswap) {
- tcg_out_modrm(s, 0x8b, r1, data_reg); /* movl */
- /* bswap data_reg */
- tcg_out_opc(s, (0xc8 + r1) | P_EXT, 0, r1, 0);
- data_reg = r1;
- }
- /* movl */
- tcg_out_modrm_offset(s, 0x89, data_reg, r0, offset);
- break;
- case 3:
- if (bswap) {
- tcg_out_mov(s, r1, data_reg);
- /* bswap data_reg */
- tcg_out_opc(s, (0xc8 + r1) | P_EXT | P_REXW, 0, r1, 0);
- data_reg = r1;
- }
- /* movq */
- tcg_out_modrm_offset(s, 0x89 | P_REXW, data_reg, r0, offset);
- break;
- default:
- tcg_abort();
- }
-
-#if defined(CONFIG_SOFTMMU)
- /* label2: */
- *label2_ptr = s->code_ptr - label2_ptr - 1;
-#endif
-}
-
-static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args,
- const int *const_args)
-{
- int c;
-
- switch(opc) {
- case INDEX_op_exit_tb:
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RAX, args[0]);
- tcg_out_goto(s, 0, tb_ret_addr);
- break;
- case INDEX_op_goto_tb:
- if (s->tb_jmp_offset) {
- /* direct jump method */
- tcg_out8(s, 0xe9); /* jmp im */
- s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
- tcg_out32(s, 0);
- } else {
- /* indirect jump method */
- /* jmp Ev */
- tcg_out_modrm_offset(s, 0xff, 4, -1,
- (tcg_target_long)(s->tb_next +
- args[0]));
- }
- s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
- break;
- case INDEX_op_call:
- if (const_args[0]) {
- tcg_out_goto(s, 1, (void *) args[0]);
- } else {
- tcg_out_modrm(s, 0xff, 2, args[0]);
- }
- break;
- case INDEX_op_jmp:
- if (const_args[0]) {
- tcg_out_goto(s, 0, (void *) args[0]);
- } else {
- tcg_out_modrm(s, 0xff, 4, args[0]);
- }
- break;
- case INDEX_op_br:
- tcg_out_jxx(s, JCC_JMP, args[0]);
- break;
- case INDEX_op_movi_i32:
- tcg_out_movi(s, TCG_TYPE_I32, args[0], (uint32_t)args[1]);
- break;
- case INDEX_op_movi_i64:
- tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
- break;
- case INDEX_op_ld8u_i32:
- case INDEX_op_ld8u_i64:
- /* movzbl */
- tcg_out_modrm_offset(s, 0xb6 | P_EXT, args[0], args[1], args[2]);
- break;
- case INDEX_op_ld8s_i32:
- /* movsbl */
- tcg_out_modrm_offset(s, 0xbe | P_EXT, args[0], args[1], args[2]);
- break;
- case INDEX_op_ld8s_i64:
- /* movsbq */
- tcg_out_modrm_offset(s, 0xbe | P_EXT | P_REXW, args[0], args[1], args[2]);
- break;
- case INDEX_op_ld16u_i32:
- case INDEX_op_ld16u_i64:
- /* movzwl */
- tcg_out_modrm_offset(s, 0xb7 | P_EXT, args[0], args[1], args[2]);
- break;
- case INDEX_op_ld16s_i32:
- /* movswl */
- tcg_out_modrm_offset(s, 0xbf | P_EXT, args[0], args[1], args[2]);
- break;
- case INDEX_op_ld16s_i64:
- /* movswq */
- tcg_out_modrm_offset(s, 0xbf | P_EXT | P_REXW, args[0], args[1], args[2]);
- break;
- case INDEX_op_ld_i32:
- case INDEX_op_ld32u_i64:
- /* movl */
- tcg_out_modrm_offset(s, 0x8b, args[0], args[1], args[2]);
- break;
- case INDEX_op_ld32s_i64:
- /* movslq */
- tcg_out_modrm_offset(s, 0x63 | P_REXW, args[0], args[1], args[2]);
- break;
- case INDEX_op_ld_i64:
- /* movq */
- tcg_out_modrm_offset(s, 0x8b | P_REXW, args[0], args[1], args[2]);
- break;
-
- case INDEX_op_st8_i32:
- case INDEX_op_st8_i64:
- /* movb */
- tcg_out_modrm_offset(s, 0x88 | P_REXB_R, args[0], args[1], args[2]);
- break;
- case INDEX_op_st16_i32:
- case INDEX_op_st16_i64:
- /* movw */
- tcg_out8(s, 0x66);
- tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]);
- break;
- case INDEX_op_st_i32:
- case INDEX_op_st32_i64:
- /* movl */
- tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]);
- break;
- case INDEX_op_st_i64:
- /* movq */
- tcg_out_modrm_offset(s, 0x89 | P_REXW, args[0], args[1], args[2]);
- break;
-
- case INDEX_op_sub_i32:
- c = ARITH_SUB;
- goto gen_arith32;
- case INDEX_op_and_i32:
- c = ARITH_AND;
- goto gen_arith32;
- case INDEX_op_or_i32:
- c = ARITH_OR;
- goto gen_arith32;
- case INDEX_op_xor_i32:
- c = ARITH_XOR;
- goto gen_arith32;
- case INDEX_op_add_i32:
- c = ARITH_ADD;
- gen_arith32:
- if (const_args[2]) {
- tgen_arithi32(s, c, args[0], args[2]);
- } else {
- tcg_out_modrm(s, 0x01 | (c << 3), args[2], args[0]);
- }
- break;
-
- case INDEX_op_sub_i64:
- c = ARITH_SUB;
- goto gen_arith64;
- case INDEX_op_and_i64:
- c = ARITH_AND;
- goto gen_arith64;
- case INDEX_op_or_i64:
- c = ARITH_OR;
- goto gen_arith64;
- case INDEX_op_xor_i64:
- c = ARITH_XOR;
- goto gen_arith64;
- case INDEX_op_add_i64:
- c = ARITH_ADD;
- gen_arith64:
- if (const_args[2]) {
- tgen_arithi64(s, c, args[0], args[2]);
- } else {
- tcg_out_modrm(s, 0x01 | (c << 3) | P_REXW, args[2], args[0]);
- }
- break;
-
- case INDEX_op_mul_i32:
- if (const_args[2]) {
- int32_t val;
- val = args[2];
- if (val == (int8_t)val) {
- tcg_out_modrm(s, 0x6b, args[0], args[0]);
- tcg_out8(s, val);
- } else {
- tcg_out_modrm(s, 0x69, args[0], args[0]);
- tcg_out32(s, val);
- }
- } else {
- tcg_out_modrm(s, 0xaf | P_EXT, args[0], args[2]);
- }
- break;
- case INDEX_op_mul_i64:
- if (const_args[2]) {
- int32_t val;
- val = args[2];
- if (val == (int8_t)val) {
- tcg_out_modrm(s, 0x6b | P_REXW, args[0], args[0]);
- tcg_out8(s, val);
- } else {
- tcg_out_modrm(s, 0x69 | P_REXW, args[0], args[0]);
- tcg_out32(s, val);
- }
- } else {
- tcg_out_modrm(s, 0xaf | P_EXT | P_REXW, args[0], args[2]);
- }
- break;
- case INDEX_op_div2_i32:
- tcg_out_modrm(s, 0xf7, 7, args[4]);
- break;
- case INDEX_op_divu2_i32:
- tcg_out_modrm(s, 0xf7, 6, args[4]);
- break;
- case INDEX_op_div2_i64:
- tcg_out_modrm(s, 0xf7 | P_REXW, 7, args[4]);
- break;
- case INDEX_op_divu2_i64:
- tcg_out_modrm(s, 0xf7 | P_REXW, 6, args[4]);
- break;
-
- case INDEX_op_shl_i32:
- c = SHIFT_SHL;
- gen_shift32:
- if (const_args[2]) {
- if (args[2] == 1) {
- tcg_out_modrm(s, 0xd1, c, args[0]);
- } else {
- tcg_out_modrm(s, 0xc1, c, args[0]);
- tcg_out8(s, args[2]);
- }
- } else {
- tcg_out_modrm(s, 0xd3, c, args[0]);
- }
- break;
- case INDEX_op_shr_i32:
- c = SHIFT_SHR;
- goto gen_shift32;
- case INDEX_op_sar_i32:
- c = SHIFT_SAR;
- goto gen_shift32;
- case INDEX_op_rotl_i32:
- c = SHIFT_ROL;
- goto gen_shift32;
- case INDEX_op_rotr_i32:
- c = SHIFT_ROR;
- goto gen_shift32;
-
- case INDEX_op_shl_i64:
- c = SHIFT_SHL;
- gen_shift64:
- if (const_args[2]) {
- if (args[2] == 1) {
- tcg_out_modrm(s, 0xd1 | P_REXW, c, args[0]);
- } else {
- tcg_out_modrm(s, 0xc1 | P_REXW, c, args[0]);
- tcg_out8(s, args[2]);
- }
- } else {
- tcg_out_modrm(s, 0xd3 | P_REXW, c, args[0]);
- }
- break;
- case INDEX_op_shr_i64:
- c = SHIFT_SHR;
- goto gen_shift64;
- case INDEX_op_sar_i64:
- c = SHIFT_SAR;
- goto gen_shift64;
- case INDEX_op_rotl_i64:
- c = SHIFT_ROL;
- goto gen_shift64;
- case INDEX_op_rotr_i64:
- c = SHIFT_ROR;
- goto gen_shift64;
-
- case INDEX_op_brcond_i32:
- tcg_out_brcond(s, args[2], args[0], args[1], const_args[1],
- args[3], 0);
- break;
- case INDEX_op_brcond_i64:
- tcg_out_brcond(s, args[2], args[0], args[1], const_args[1],
- args[3], P_REXW);
- break;
-
- case INDEX_op_bswap16_i32:
- case INDEX_op_bswap16_i64:
- tcg_out8(s, 0x66);
- tcg_out_modrm(s, 0xc1, SHIFT_ROL, args[0]);
- tcg_out8(s, 8);
- break;
- case INDEX_op_bswap32_i32:
- case INDEX_op_bswap32_i64:
- tcg_out_opc(s, (0xc8 + (args[0] & 7)) | P_EXT, 0, args[0], 0);
- break;
- case INDEX_op_bswap64_i64:
- tcg_out_opc(s, (0xc8 + (args[0] & 7)) | P_EXT | P_REXW, 0, args[0], 0);
- break;
-
- case INDEX_op_neg_i32:
- tcg_out_modrm(s, 0xf7, 3, args[0]);
- break;
- case INDEX_op_neg_i64:
- tcg_out_modrm(s, 0xf7 | P_REXW, 3, args[0]);
- break;
-
- case INDEX_op_not_i32:
- tcg_out_modrm(s, 0xf7, 2, args[0]);
- break;
- case INDEX_op_not_i64:
- tcg_out_modrm(s, 0xf7 | P_REXW, 2, args[0]);
- break;
-
- case INDEX_op_ext8s_i32:
- tcg_out_modrm(s, 0xbe | P_EXT | P_REXB_RM, args[0], args[1]);
- break;
- case INDEX_op_ext16s_i32:
- tcg_out_modrm(s, 0xbf | P_EXT, args[0], args[1]);
- break;
- case INDEX_op_ext8s_i64:
- tcg_out_modrm(s, 0xbe | P_EXT | P_REXW, args[0], args[1]);
- break;
- case INDEX_op_ext16s_i64:
- tcg_out_modrm(s, 0xbf | P_EXT | P_REXW, args[0], args[1]);
- break;
- case INDEX_op_ext32s_i64:
- tcg_out_modrm(s, 0x63 | P_REXW, args[0], args[1]);
- break;
- case INDEX_op_ext8u_i32:
- case INDEX_op_ext8u_i64:
- tcg_out_modrm(s, 0xb6 | P_EXT | P_REXB_RM, args[0], args[1]);
- break;
- case INDEX_op_ext16u_i32:
- case INDEX_op_ext16u_i64:
- tcg_out_modrm(s, 0xb7 | P_EXT, args[0], args[1]);
- break;
- case INDEX_op_ext32u_i64:
- tcg_out_modrm(s, 0x8b, args[0], args[1]);
- break;
-
- case INDEX_op_setcond_i32:
- tcg_out_setcond(s, args[3], args[0], args[1], args[2],
- const_args[2], 0);
- break;
- case INDEX_op_setcond_i64:
- tcg_out_setcond(s, args[3], args[0], args[1], args[2],
- const_args[2], P_REXW);
- break;
-
- case INDEX_op_qemu_ld8u:
- tcg_out_qemu_ld(s, args, 0);
- break;
- case INDEX_op_qemu_ld8s:
- tcg_out_qemu_ld(s, args, 0 | 4);
- break;
- case INDEX_op_qemu_ld16u:
- tcg_out_qemu_ld(s, args, 1);
- break;
- case INDEX_op_qemu_ld16s:
- tcg_out_qemu_ld(s, args, 1 | 4);
- break;
- case INDEX_op_qemu_ld32:
- case INDEX_op_qemu_ld32u:
- tcg_out_qemu_ld(s, args, 2);
- break;
- case INDEX_op_qemu_ld32s:
- tcg_out_qemu_ld(s, args, 2 | 4);
- break;
- case INDEX_op_qemu_ld64:
- tcg_out_qemu_ld(s, args, 3);
- break;
-
- case INDEX_op_qemu_st8:
- tcg_out_qemu_st(s, args, 0);
- break;
- case INDEX_op_qemu_st16:
- tcg_out_qemu_st(s, args, 1);
- break;
- case INDEX_op_qemu_st32:
- tcg_out_qemu_st(s, args, 2);
- break;
- case INDEX_op_qemu_st64:
- tcg_out_qemu_st(s, args, 3);
- break;
-
- default:
- tcg_abort();
- }
-}
-
-static int tcg_target_callee_save_regs[] = {
- TCG_REG_RBP,
- TCG_REG_RBX,
- TCG_REG_R12,
- TCG_REG_R13,
- /* TCG_REG_R14, */ /* currently used for the global env, so no
- need to save */
- TCG_REG_R15,
-};
-
-static inline void tcg_out_push(TCGContext *s, int reg)
-{
- tcg_out_opc(s, (0x50 + (reg & 7)), 0, reg, 0);
-}
-
-static inline void tcg_out_pop(TCGContext *s, int reg)
-{
- tcg_out_opc(s, (0x58 + (reg & 7)), 0, reg, 0);
-}
-
-/* Generate global QEMU prologue and epilogue code */
-void tcg_target_qemu_prologue(TCGContext *s)
-{
- int i, frame_size, push_size, stack_addend;
-
- /* TB prologue */
- /* save all callee saved registers */
- for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
- tcg_out_push(s, tcg_target_callee_save_regs[i]);
-
- }
- /* reserve some stack space */
- push_size = 8 + ARRAY_SIZE(tcg_target_callee_save_regs) * 8;
- frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE;
- frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
- ~(TCG_TARGET_STACK_ALIGN - 1);
- stack_addend = frame_size - push_size;
- tcg_out_addi(s, TCG_REG_RSP, -stack_addend);
-
- tcg_out_modrm(s, 0xff, 4, TCG_REG_RDI); /* jmp *%rdi */
-
- /* TB epilogue */
- tb_ret_addr = s->code_ptr;
- tcg_out_addi(s, TCG_REG_RSP, stack_addend);
- for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) {
- tcg_out_pop(s, tcg_target_callee_save_regs[i]);
- }
- tcg_out8(s, 0xc3); /* ret */
-}
-
-static const TCGTargetOpDef x86_64_op_defs[] = {
- { INDEX_op_exit_tb, { } },
- { INDEX_op_goto_tb, { } },
- { INDEX_op_call, { "ri" } }, /* XXX: might need a specific constant constraint */
- { INDEX_op_jmp, { "ri" } }, /* XXX: might need a specific constant constraint */
- { INDEX_op_br, { } },
-
- { INDEX_op_mov_i32, { "r", "r" } },
- { INDEX_op_movi_i32, { "r" } },
- { INDEX_op_ld8u_i32, { "r", "r" } },
- { INDEX_op_ld8s_i32, { "r", "r" } },
- { INDEX_op_ld16u_i32, { "r", "r" } },
- { INDEX_op_ld16s_i32, { "r", "r" } },
- { INDEX_op_ld_i32, { "r", "r" } },
- { INDEX_op_st8_i32, { "r", "r" } },
- { INDEX_op_st16_i32, { "r", "r" } },
- { INDEX_op_st_i32, { "r", "r" } },
-
- { INDEX_op_add_i32, { "r", "0", "ri" } },
- { INDEX_op_mul_i32, { "r", "0", "ri" } },
- { INDEX_op_div2_i32, { "a", "d", "0", "1", "r" } },
- { INDEX_op_divu2_i32, { "a", "d", "0", "1", "r" } },
- { INDEX_op_sub_i32, { "r", "0", "ri" } },
- { INDEX_op_and_i32, { "r", "0", "ri" } },
- { INDEX_op_or_i32, { "r", "0", "ri" } },
- { INDEX_op_xor_i32, { "r", "0", "ri" } },
-
- { INDEX_op_shl_i32, { "r", "0", "ci" } },
- { INDEX_op_shr_i32, { "r", "0", "ci" } },
- { INDEX_op_sar_i32, { "r", "0", "ci" } },
- { INDEX_op_rotl_i32, { "r", "0", "ci" } },
- { INDEX_op_rotr_i32, { "r", "0", "ci" } },
-
- { INDEX_op_brcond_i32, { "r", "ri" } },
-
- { INDEX_op_mov_i64, { "r", "r" } },
- { INDEX_op_movi_i64, { "r" } },
- { INDEX_op_ld8u_i64, { "r", "r" } },
- { INDEX_op_ld8s_i64, { "r", "r" } },
- { INDEX_op_ld16u_i64, { "r", "r" } },
- { INDEX_op_ld16s_i64, { "r", "r" } },
- { INDEX_op_ld32u_i64, { "r", "r" } },
- { INDEX_op_ld32s_i64, { "r", "r" } },
- { INDEX_op_ld_i64, { "r", "r" } },
- { INDEX_op_st8_i64, { "r", "r" } },
- { INDEX_op_st16_i64, { "r", "r" } },
- { INDEX_op_st32_i64, { "r", "r" } },
- { INDEX_op_st_i64, { "r", "r" } },
-
- { INDEX_op_add_i64, { "r", "0", "re" } },
- { INDEX_op_mul_i64, { "r", "0", "re" } },
- { INDEX_op_div2_i64, { "a", "d", "0", "1", "r" } },
- { INDEX_op_divu2_i64, { "a", "d", "0", "1", "r" } },
- { INDEX_op_sub_i64, { "r", "0", "re" } },
- { INDEX_op_and_i64, { "r", "0", "reZ" } },
- { INDEX_op_or_i64, { "r", "0", "re" } },
- { INDEX_op_xor_i64, { "r", "0", "re" } },
-
- { INDEX_op_shl_i64, { "r", "0", "ci" } },
- { INDEX_op_shr_i64, { "r", "0", "ci" } },
- { INDEX_op_sar_i64, { "r", "0", "ci" } },
- { INDEX_op_rotl_i64, { "r", "0", "ci" } },
- { INDEX_op_rotr_i64, { "r", "0", "ci" } },
-
- { INDEX_op_brcond_i64, { "r", "re" } },
-
- { INDEX_op_bswap16_i32, { "r", "0" } },
- { INDEX_op_bswap16_i64, { "r", "0" } },
- { INDEX_op_bswap32_i32, { "r", "0" } },
- { INDEX_op_bswap32_i64, { "r", "0" } },
- { INDEX_op_bswap64_i64, { "r", "0" } },
-
- { INDEX_op_neg_i32, { "r", "0" } },
- { INDEX_op_neg_i64, { "r", "0" } },
-
- { INDEX_op_not_i32, { "r", "0" } },
- { INDEX_op_not_i64, { "r", "0" } },
-
- { INDEX_op_ext8s_i32, { "r", "r"} },
- { INDEX_op_ext16s_i32, { "r", "r"} },
- { INDEX_op_ext8s_i64, { "r", "r"} },
- { INDEX_op_ext16s_i64, { "r", "r"} },
- { INDEX_op_ext32s_i64, { "r", "r"} },
- { INDEX_op_ext8u_i32, { "r", "r"} },
- { INDEX_op_ext16u_i32, { "r", "r"} },
- { INDEX_op_ext8u_i64, { "r", "r"} },
- { INDEX_op_ext16u_i64, { "r", "r"} },
- { INDEX_op_ext32u_i64, { "r", "r"} },
-
- { INDEX_op_setcond_i32, { "r", "r", "ri" } },
- { INDEX_op_setcond_i64, { "r", "r", "re" } },
-
- { INDEX_op_qemu_ld8u, { "r", "L" } },
- { INDEX_op_qemu_ld8s, { "r", "L" } },
- { INDEX_op_qemu_ld16u, { "r", "L" } },
- { INDEX_op_qemu_ld16s, { "r", "L" } },
- { INDEX_op_qemu_ld32, { "r", "L" } },
- { INDEX_op_qemu_ld32u, { "r", "L" } },
- { INDEX_op_qemu_ld32s, { "r", "L" } },
- { INDEX_op_qemu_ld64, { "r", "L" } },
-
- { INDEX_op_qemu_st8, { "L", "L" } },
- { INDEX_op_qemu_st16, { "L", "L" } },
- { INDEX_op_qemu_st32, { "L", "L" } },
- { INDEX_op_qemu_st64, { "L", "L" } },
-
- { -1 },
-};
-
-void tcg_target_init(TCGContext *s)
-{
-#if !defined(CONFIG_USER_ONLY)
- /* fail safe */
- if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry))
- tcg_abort();
-#endif
-
- tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffff);
- tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffff);
- tcg_regset_set32(tcg_target_call_clobber_regs, 0,
- (1 << TCG_REG_RDI) |
- (1 << TCG_REG_RSI) |
- (1 << TCG_REG_RDX) |
- (1 << TCG_REG_RCX) |
- (1 << TCG_REG_R8) |
- (1 << TCG_REG_R9) |
- (1 << TCG_REG_RAX) |
- (1 << TCG_REG_R10) |
- (1 << TCG_REG_R11));
-
- tcg_regset_clear(s->reserved_regs);
- tcg_regset_set_reg(s->reserved_regs, TCG_REG_RSP);
-
- tcg_add_target_add_op_defs(x86_64_op_defs);
-}
diff --git a/tcg/x86_64/tcg-target.h b/tcg/x86_64/tcg-target.h
deleted file mode 100644
index e0eabaa..0000000
--- a/tcg/x86_64/tcg-target.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Tiny Code Generator for QEMU
- *
- * Copyright (c) 2008 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#define TCG_TARGET_X86_64 1
-
-#define TCG_TARGET_REG_BITS 64
-//#define TCG_TARGET_WORDS_BIGENDIAN
-
-#define TCG_TARGET_NB_REGS 16
-
-enum {
- TCG_REG_RAX = 0,
- TCG_REG_RCX,
- TCG_REG_RDX,
- TCG_REG_RBX,
- TCG_REG_RSP,
- TCG_REG_RBP,
- TCG_REG_RSI,
- TCG_REG_RDI,
- TCG_REG_R8,
- TCG_REG_R9,
- TCG_REG_R10,
- TCG_REG_R11,
- TCG_REG_R12,
- TCG_REG_R13,
- TCG_REG_R14,
- TCG_REG_R15,
-};
-
-#define TCG_CT_CONST_S32 0x100
-#define TCG_CT_CONST_U32 0x200
-
-/* used for function call generation */
-#define TCG_REG_CALL_STACK TCG_REG_RSP
-#define TCG_TARGET_STACK_ALIGN 16
-#define TCG_TARGET_CALL_STACK_OFFSET 0
-
-/* optional instructions */
-#define TCG_TARGET_HAS_div2_i32
-#define TCG_TARGET_HAS_div2_i64
-#define TCG_TARGET_HAS_bswap16_i32
-#define TCG_TARGET_HAS_bswap16_i64
-#define TCG_TARGET_HAS_bswap32_i32
-#define TCG_TARGET_HAS_bswap32_i64
-#define TCG_TARGET_HAS_bswap64_i64
-#define TCG_TARGET_HAS_neg_i32
-#define TCG_TARGET_HAS_neg_i64
-#define TCG_TARGET_HAS_not_i32
-#define TCG_TARGET_HAS_not_i64
-#define TCG_TARGET_HAS_ext8s_i32
-#define TCG_TARGET_HAS_ext16s_i32
-#define TCG_TARGET_HAS_ext8s_i64
-#define TCG_TARGET_HAS_ext16s_i64
-#define TCG_TARGET_HAS_ext32s_i64
-#define TCG_TARGET_HAS_ext8u_i32
-#define TCG_TARGET_HAS_ext16u_i32
-#define TCG_TARGET_HAS_ext8u_i64
-#define TCG_TARGET_HAS_ext16u_i64
-#define TCG_TARGET_HAS_ext32u_i64
-#define TCG_TARGET_HAS_rot_i32
-#define TCG_TARGET_HAS_rot_i64
-
-// #define TCG_TARGET_HAS_andc_i32
-// #define TCG_TARGET_HAS_andc_i64
-// #define TCG_TARGET_HAS_orc_i32
-// #define TCG_TARGET_HAS_orc_i64
-// #define TCG_TARGET_HAS_eqv_i32
-// #define TCG_TARGET_HAS_eqv_i64
-// #define TCG_TARGET_HAS_nand_i32
-// #define TCG_TARGET_HAS_nand_i64
-// #define TCG_TARGET_HAS_nor_i32
-// #define TCG_TARGET_HAS_nor_i64
-
-#define TCG_TARGET_HAS_GUEST_BASE
-
-/* Note: must be synced with dyngen-exec.h */
-#define TCG_AREG0 TCG_REG_R14
-
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-}
diff --git a/translate-all.c b/translate-all.c
index 91cbbc4..efcfb9a 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -41,22 +41,6 @@ target_ulong gen_opc_pc[OPC_BUF_SIZE];
uint16_t gen_opc_icount[OPC_BUF_SIZE];
uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
-/* XXX: suppress that */
-unsigned long code_gen_max_block_size(void)
-{
- static unsigned long max;
-
- if (max == 0) {
- max = TCG_MAX_OP_SIZE;
-#define DEF(s, n, copy_size) max = copy_size > max? copy_size : max;
-#include "tcg-opc.h"
-#undef DEF
- max *= OPC_MAX_SIZE;
- }
-
- return max;
-}
-
void cpu_gen_init(void)
{
tcg_context_init(&tcg_ctx);
diff --git a/vl.c b/vl.c
index 0a9862f..df18198 100644
--- a/vl.c
+++ b/vl.c
@@ -34,7 +34,6 @@
#ifndef _WIN32
#include <libgen.h>
-#include <pwd.h>
#include <sys/times.h>
#include <sys/wait.h>
#include <termios.h>
@@ -60,7 +59,6 @@
#ifdef __linux__
#include <pty.h>
#include <malloc.h>
-#include <sys/prctl.h>
#include <linux/ppdev.h>
#include <linux/parport.h>
@@ -70,7 +68,6 @@
#include <sys/ethernet.h>
#include <sys/sockio.h>
#include <netinet/arp.h>
-#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h> // must come after ip.h
@@ -149,6 +146,7 @@ int main(int argc, char **argv)
#include "qemu-option.h"
#include "qemu-config.h"
#include "qemu-objects.h"
+#include "qemu-options.h"
#ifdef CONFIG_LINUX
#include "fsdev/qemu-fsdev.h"
#endif
@@ -213,9 +211,6 @@ int no_shutdown = 0;
int cursor_hide = 1;
int graphic_rotate = 0;
uint8_t irq0override = 1;
-#ifndef _WIN32
-int daemonize = 0;
-#endif
const char *watchdog;
const char *option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
@@ -284,22 +279,6 @@ static int default_driver_check(QemuOpts *opts, void *opaque)
}
/***********************************************************/
-
-static void set_proc_name(const char *s)
-{
-#if defined(__linux__) && defined(PR_SET_NAME)
- char name[16];
- if (!s)
- return;
- name[sizeof(name) - 1] = 0;
- strncpy(name, s, sizeof(name));
- /* Could rewrite argv[0] too, but that's a bit more complicated.
- This simple way is enough for `top'. */
- prctl(PR_SET_NAME, name);
-#endif
-}
-
-/***********************************************************/
/* real time host monotonic timer */
/* compute with 96 bit intermediate result: (a*b)/c */
@@ -1014,86 +993,6 @@ int qemu_set_fd_handler(int fd,
return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
}
-#ifdef _WIN32
-/***********************************************************/
-/* Polling handling */
-
-typedef struct PollingEntry {
- PollingFunc *func;
- void *opaque;
- struct PollingEntry *next;
-} PollingEntry;
-
-static PollingEntry *first_polling_entry;
-
-int qemu_add_polling_cb(PollingFunc *func, void *opaque)
-{
- PollingEntry **ppe, *pe;
- pe = qemu_mallocz(sizeof(PollingEntry));
- pe->func = func;
- pe->opaque = opaque;
- for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
- *ppe = pe;
- return 0;
-}
-
-void qemu_del_polling_cb(PollingFunc *func, void *opaque)
-{
- PollingEntry **ppe, *pe;
- for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
- pe = *ppe;
- if (pe->func == func && pe->opaque == opaque) {
- *ppe = pe->next;
- qemu_free(pe);
- break;
- }
- }
-}
-
-/***********************************************************/
-/* Wait objects support */
-typedef struct WaitObjects {
- int num;
- HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
- WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
- void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
-} WaitObjects;
-
-static WaitObjects wait_objects = {0};
-
-int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
-{
- WaitObjects *w = &wait_objects;
-
- if (w->num >= MAXIMUM_WAIT_OBJECTS)
- return -1;
- w->events[w->num] = handle;
- w->func[w->num] = func;
- w->opaque[w->num] = opaque;
- w->num++;
- return 0;
-}
-
-void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
-{
- int i, found;
- WaitObjects *w = &wait_objects;
-
- found = 0;
- for (i = 0; i < w->num; i++) {
- if (w->events[i] == handle)
- found = 1;
- if (found) {
- w->events[i] = w->events[i + 1];
- w->func[i] = w->func[i + 1];
- w->opaque[i] = w->opaque[i + 1];
- }
- }
- if (found)
- w->num--;
-}
-#endif
-
/***********************************************************/
/* machine registration */
@@ -1319,56 +1218,6 @@ void qemu_system_powerdown_request(void)
qemu_notify_event();
}
-#ifdef _WIN32
-static void host_main_loop_wait(int *timeout)
-{
- int ret, ret2, i;
- PollingEntry *pe;
-
-
- /* XXX: need to suppress polling by better using win32 events */
- ret = 0;
- for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
- ret |= pe->func(pe->opaque);
- }
- if (ret == 0) {
- int err;
- WaitObjects *w = &wait_objects;
-
- ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
- if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
- if (w->func[ret - WAIT_OBJECT_0])
- w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
-
- /* Check for additional signaled events */
- for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
-
- /* Check if event is signaled */
- ret2 = WaitForSingleObject(w->events[i], 0);
- if(ret2 == WAIT_OBJECT_0) {
- if (w->func[i])
- w->func[i](w->opaque[i]);
- } else if (ret2 == WAIT_TIMEOUT) {
- } else {
- err = GetLastError();
- fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
- }
- }
- } else if (ret == WAIT_TIMEOUT) {
- } else {
- err = GetLastError();
- fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
- }
- }
-
- *timeout = 0;
-}
-#else
-static void host_main_loop_wait(int *timeout)
-{
-}
-#endif
-
void main_loop_wait(int nonblocking)
{
IOHandlerRecord *ioh;
@@ -1384,7 +1233,7 @@ void main_loop_wait(int nonblocking)
qemu_bh_update_timeout(&timeout);
}
- host_main_loop_wait(&timeout);
+ os_host_main_loop_wait(&timeout);
/* poll any events */
/* XXX: separate device handlers from system ones */
@@ -1523,7 +1372,7 @@ static void help(int exitcode)
#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask) \
opt_help
#define DEFHEADING(text) stringify(text) "\n"
-#include "qemu-options.h"
+#include "qemu-options.def"
#undef DEF
#undef DEFHEADING
#undef GEN_DOCS
@@ -1547,16 +1396,6 @@ static void help(int exitcode)
#define HAS_ARG 0x0001
-enum {
-#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask) \
- opt_enum,
-#define DEFHEADING(text)
-#include "qemu-options.h"
-#undef DEF
-#undef DEFHEADING
-#undef GEN_DOCS
-};
-
typedef struct QEMUOption {
const char *name;
int flags;
@@ -1569,7 +1408,7 @@ static const QEMUOption qemu_options[] = {
#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask) \
{ option, opt_arg, opt_enum, arch_mask },
#define DEFHEADING(text)
-#include "qemu-options.h"
+#include "qemu-options.def"
#undef DEF
#undef DEFHEADING
#undef GEN_DOCS
@@ -1634,132 +1473,6 @@ static int balloon_parse(const char *arg)
return -1;
}
-#ifdef _WIN32
-static BOOL WINAPI qemu_ctrl_handler(DWORD type)
-{
- exit(STATUS_CONTROL_C_EXIT);
- return TRUE;
-}
-#endif
-
-#ifndef _WIN32
-
-static void termsig_handler(int signal)
-{
- qemu_system_shutdown_request();
-}
-
-static void sigchld_handler(int signal)
-{
- waitpid(-1, NULL, WNOHANG);
-}
-
-static void sighandler_setup(void)
-{
- struct sigaction act;
-
- memset(&act, 0, sizeof(act));
- act.sa_handler = termsig_handler;
- sigaction(SIGINT, &act, NULL);
- sigaction(SIGHUP, &act, NULL);
- sigaction(SIGTERM, &act, NULL);
-
- act.sa_handler = sigchld_handler;
- act.sa_flags = SA_NOCLDSTOP;
- sigaction(SIGCHLD, &act, NULL);
-}
-
-#endif
-
-#ifdef _WIN32
-/* Look for support files in the same directory as the executable. */
-static char *find_datadir(const char *argv0)
-{
- char *p;
- char buf[MAX_PATH];
- DWORD len;
-
- len = GetModuleFileName(NULL, buf, sizeof(buf) - 1);
- if (len == 0) {
- return NULL;
- }
-
- buf[len] = 0;
- p = buf + len - 1;
- while (p != buf && *p != '\\')
- p--;
- *p = 0;
- if (access(buf, R_OK) == 0) {
- return qemu_strdup(buf);
- }
- return NULL;
-}
-#else /* !_WIN32 */
-
-/* Find a likely location for support files using the location of the binary.
- For installed binaries this will be "$bindir/../share/qemu". When
- running from the build tree this will be "$bindir/../pc-bios". */
-#define SHARE_SUFFIX "/share/qemu"
-#define BUILD_SUFFIX "/pc-bios"
-static char *find_datadir(const char *argv0)
-{
- char *dir;
- char *p = NULL;
- char *res;
- char buf[PATH_MAX];
- size_t max_len;
-
-#if defined(__linux__)
- {
- int len;
- len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
- if (len > 0) {
- buf[len] = 0;
- p = buf;
- }
- }
-#elif defined(__FreeBSD__)
- {
- static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
- size_t len = sizeof(buf) - 1;
-
- *buf = '\0';
- if (!sysctl(mib, sizeof(mib)/sizeof(*mib), buf, &len, NULL, 0) &&
- *buf) {
- buf[sizeof(buf) - 1] = '\0';
- p = buf;
- }
- }
-#endif
- /* If we don't have any way of figuring out the actual executable
- location then try argv[0]. */
- if (!p) {
- p = realpath(argv0, buf);
- if (!p) {
- return NULL;
- }
- }
- dir = dirname(p);
- dir = dirname(dir);
-
- max_len = strlen(dir) +
- MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
- res = qemu_mallocz(max_len);
- snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
- if (access(res, R_OK)) {
- snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
- if (access(res, R_OK)) {
- qemu_free(res);
- res = NULL;
- }
- }
-
- return res;
-}
-#undef SHARE_SUFFIX
-#undef BUILD_SUFFIX
-#endif
-
char *qemu_find_file(int type, const char *name)
{
int len;
@@ -2085,18 +1798,9 @@ int main(int argc, char **argv, char **envp)
const char *loadvm = NULL;
QEMUMachine *machine;
const char *cpu_model;
-#ifndef _WIN32
- int fds[2];
-#endif
int tb_size;
const char *pid_file = NULL;
const char *incoming = NULL;
-#ifndef _WIN32
- int fd = 0;
- struct passwd *pwd = NULL;
- const char *chroot_dir = NULL;
- const char *run_as = NULL;
-#endif
int show_vnc_port = 0;
int defconfig = 1;
@@ -2107,35 +1811,7 @@ int main(int argc, char **argv, char **envp)
qemu_cache_utils_init(envp);
QLIST_INIT (&vm_change_state_head);
-#ifndef _WIN32
- {
- struct sigaction act;
- sigfillset(&act.sa_mask);
- act.sa_flags = 0;
- act.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &act, NULL);
- }
-#else
- SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE);
- /* Note: cpu_interrupt() is currently not SMP safe, so we force
- QEMU to run on a single CPU */
- {
- HANDLE h;
- DWORD mask, smask;
- int i;
- h = GetCurrentProcess();
- if (GetProcessAffinityMask(h, &mask, &smask)) {
- for(i = 0; i < 32; i++) {
- if (mask & (1 << i))
- break;
- }
- if (i != 32) {
- mask = 1 << i;
- SetProcessAffinityMask(h, mask);
- }
- }
- }
-#endif
+ os_setup_early_signal_handling();
module_call_init(MODULE_INIT_MACHINE);
machine = find_default_machine();
@@ -2426,12 +2102,6 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_bootp:
legacy_bootp_filename = optarg;
break;
-#ifndef _WIN32
- case QEMU_OPTION_smb:
- if (net_slirp_smb(optarg) < 0)
- exit(1);
- break;
-#endif
case QEMU_OPTION_redir:
if (net_slirp_redir(optarg) < 0)
exit(1);
@@ -2796,11 +2466,6 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
break;
-#ifndef _WIN32
- case QEMU_OPTION_daemonize:
- daemonize = 1;
- break;
-#endif
case QEMU_OPTION_option_rom:
if (nb_option_roms >= MAX_OPTION_ROMS) {
fprintf(stderr, "Too many option ROMs\n");
@@ -2823,7 +2488,7 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
p += 8;
- set_proc_name(p);
+ os_set_proc_name(p);
}
}
break;
@@ -2873,14 +2538,6 @@ int main(int argc, char **argv, char **envp)
default_cdrom = 0;
default_sdcard = 0;
break;
-#ifndef _WIN32
- case QEMU_OPTION_chroot:
- chroot_dir = optarg;
- break;
- case QEMU_OPTION_runas:
- run_as = optarg;
- break;
-#endif
case QEMU_OPTION_xen_domid:
if (!(xen_available())) {
printf("Option %s not supported for this target\n", popt->name);
@@ -2928,6 +2585,8 @@ int main(int argc, char **argv, char **envp)
fclose(fp);
break;
}
+ default:
+ os_parse_cmd_args(popt->index, optarg);
}
}
}
@@ -2936,11 +2595,11 @@ int main(int argc, char **argv, char **envp)
/* If no data_dir is specified then try to find it relative to the
executable path. */
if (!data_dir) {
- data_dir = find_datadir(argv[0]);
+ data_dir = os_find_datadir(argv[0]);
}
/* If all else fails use the install patch specified when building. */
if (!data_dir) {
- data_dir = CONFIG_QEMU_SHAREDIR;
+ data_dir = CONFIG_QEMU_DATADIR;
}
/*
@@ -3021,64 +2680,10 @@ int main(int argc, char **argv, char **envp)
}
#endif
-#ifndef _WIN32
- if (daemonize) {
- pid_t pid;
-
- if (pipe(fds) == -1)
- exit(1);
-
- pid = fork();
- if (pid > 0) {
- uint8_t status;
- ssize_t len;
-
- close(fds[1]);
-
- again:
- len = read(fds[0], &status, 1);
- if (len == -1 && (errno == EINTR))
- goto again;
-
- if (len != 1)
- exit(1);
- else if (status == 1) {
- fprintf(stderr, "Could not acquire pidfile: %s\n", strerror(errno));
- exit(1);
- } else
- exit(0);
- } else if (pid < 0)
- exit(1);
-
- close(fds[0]);
- qemu_set_cloexec(fds[1]);
-
- setsid();
-
- pid = fork();
- if (pid > 0)
- exit(0);
- else if (pid < 0)
- exit(1);
-
- umask(027);
-
- signal(SIGTSTP, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
- signal(SIGTTIN, SIG_IGN);
- }
-#endif
+ os_daemonize();
if (pid_file && qemu_create_pidfile(pid_file) != 0) {
-#ifndef _WIN32
- if (daemonize) {
- uint8_t status = 1;
- if (write(fds[1], &status, 1) != 1) {
- perror("daemonize. Writing to pipe\n");
- }
- } else
-#endif
- fprintf(stderr, "Could not acquire pid file: %s\n", strerror(errno));
+ os_pidfile_error();
exit(1);
}
@@ -3110,10 +2715,7 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
-#ifndef _WIN32
- /* Win32 doesn't support line-buffering and requires size >= 2 */
- setvbuf(stdout, NULL, _IOLBF, 0);
-#endif
+ os_set_line_buffering();
if (init_timer_alarm() < 0) {
fprintf(stderr, "could not initialize alarm timer\n");
@@ -3240,10 +2842,8 @@ int main(int argc, char **argv, char **envp)
cpu_synchronize_all_post_init();
-#ifndef _WIN32
/* must be after terminal init, SDL library changes signal handlers */
- sighandler_setup();
-#endif
+ os_setup_signal_handling();
set_numa_modes();
@@ -3311,6 +2911,7 @@ int main(int argc, char **argv, char **envp)
if (dcl->dpy_refresh != NULL) {
ds->gui_timer = qemu_new_timer(rt_clock, gui_update, ds);
qemu_mod_timer(ds->gui_timer, qemu_get_clock(rt_clock));
+ break;
}
dcl = dcl->next;
}
@@ -3348,70 +2949,7 @@ int main(int argc, char **argv, char **envp)
vm_start();
}
-#ifndef _WIN32
- if (daemonize) {
- uint8_t status = 0;
- ssize_t len;
-
- again1:
- len = write(fds[1], &status, 1);
- if (len == -1 && (errno == EINTR))
- goto again1;
-
- if (len != 1)
- exit(1);
-
- if (chdir("/")) {
- perror("not able to chdir to /");
- exit(1);
- }
- TFR(fd = qemu_open("/dev/null", O_RDWR));
- if (fd == -1)
- exit(1);
- }
-
- if (run_as) {
- pwd = getpwnam(run_as);
- if (!pwd) {
- fprintf(stderr, "User \"%s\" doesn't exist\n", run_as);
- exit(1);
- }
- }
-
- if (chroot_dir) {
- if (chroot(chroot_dir) < 0) {
- fprintf(stderr, "chroot failed\n");
- exit(1);
- }
- if (chdir("/")) {
- perror("not able to chdir to /");
- exit(1);
- }
- }
-
- if (run_as) {
- if (setgid(pwd->pw_gid) < 0) {
- fprintf(stderr, "Failed to setgid(%d)\n", pwd->pw_gid);
- exit(1);
- }
- if (setuid(pwd->pw_uid) < 0) {
- fprintf(stderr, "Failed to setuid(%d)\n", pwd->pw_uid);
- exit(1);
- }
- if (setuid(0) != -1) {
- fprintf(stderr, "Dropping privileges failed\n");
- exit(1);
- }
- }
-
- if (daemonize) {
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
-
- close(fd);
- }
-#endif
+ os_setup_post();
main_loop();
quit_timers();
diff --git a/vnc-encoding-tight.c b/vnc-encoding-tight.c
index e8604a8..faba483 100644
--- a/vnc-encoding-tight.c
+++ b/vnc-encoding-tight.c
@@ -26,8 +26,6 @@
* THE SOFTWARE.
*/
-#include <stdbool.h>
-
#include "qdict.h"
#include "qint.h"
#include "vnc.h"
OpenPOWER on IntegriCloud