diff options
91 files changed, 5976 insertions, 3645 deletions
diff --git a/Makefile.objs b/Makefile.objs index 54dec26f4f..2bfb6d1808 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 d06c67988f..478b89d4d8 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 b150d8240c..8ebaeb38c0 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 8325f75f80..98fed944b1 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 05cc3d92b7..aff9f13b18 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 109e77753e..0b60e45fa6 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; } @@ -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 c776605e05..026980a552 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 2f052ae615..0098e683e2 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 0700a2d9bb..5bfef3f6fe 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 4565dd0605..a775582be7 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); @@ -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)); } @@ -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 7d59c96ca1..3ae4105042 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 0000000000..2ef17f606c --- /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 0000000000..e9caf8dee8 --- /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 a74d834811..97afa2cd9f 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" @@ -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 b88d00aa54..01bf92942f 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 = { @@ -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 cfd95b4ad4..d7bc102c22 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 @@ -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 c3e6a70e3d..c3459bf605 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 6f46a68e02..575968c041 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 ead3a00c3d..22db7a2f7a 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 a8f9d152dd..23de7f0f30 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 a747de596c..293d99ebee 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 f1fcfcd2ed..5a96dea003 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 a1b665cd41..dc980e6498 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 */ @@ -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 93344b1151..cdde991aa5 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 16c9950740..bb9e15ffd8 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]); @@ -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 9f80e159ad..c60fd8deef 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 2faefa51b1..8e31e36ea5 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 cb664e6207..06ba48103d 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 a93b5458b2..ff08c40681 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 422cd53400..da5297b498 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> @@ -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 9d649205a7..c736f42900 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 b55d76373e..70b9b6f967 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 610ffea6db..f7e7a68d40 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); @@ -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 0f23fc9cd9..403c8d3b96 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 8222cb92f1..e94f1eed5c 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 93bde62cd1..a8813b4fbf 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 @@ -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", @@ -20,7 +20,6 @@ #define NBD_H #include <sys/types.h> -#include <stdbool.h> #include <qemu-common.h> #include "block_int.h" @@ -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; } } @@ -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 0000000000..804e20c189 --- /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 0000000000..d98fd77c12 --- /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 8aebe51ee5..c10936344d 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 4dcb90645c..fbdd48a021 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 a4888e5e5c..d133f35f4c 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 f6a94f2b83..9f62b94862 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 0000000000..c96f994c9b --- /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 0000000000..ed5c058bc3 --- /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 0000000000..6323f7f1a6 --- /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 @@ -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 86dd84f345..8abcdf0128 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]); @@ -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 0eccca5cdb..a28e2ff333 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 063a2402ba..a62d57cf8a 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 38c6016574..708b0a11e9 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 33167977f2..ff8c8c8a80 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 7285636b68..c21b8e43ff 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 8102f03c26..ea221ab53f 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 ab47b1a3ab..a6ba75dfbc 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 c57de02eaa..a7f46974e3 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 2bfdd5002f..d09d6ed546 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 c95ecb1bdb..d43d72deea 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 8d23f47107..a3af5b222e 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 558c21f67f..7f4653e342 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 3600c35231..bb19a950bf 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 ca1d7306ea..bfafbfcbae 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 905f48b3b3..a0f38771ee 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 f38eb2888d..2af7a2e818 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 2b8592892e..2e5bb9f884 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 0b6c61fbd1..0483d6bd78 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 265194afca..6f08aa41d3 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 d8a29558bb..d7fe0c71ca 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 e460d44257..5f1353adf8 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 674c73a527..2a98fed909 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 @@ -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) @@ -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 3892f7586c..0000000000 --- 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 e0eabaa1b4..0000000000 --- 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 91cbbc4929..efcfb9adcd 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); @@ -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 e8604a85a9..faba4834cd 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" |