summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-03-06 23:23:54 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-03-06 23:23:54 +0000
commit7d13299d07a9c3c42277207ae7a691f0501a70b2 (patch)
tree981b791299c674712bacc00292de4afc6cc436ec
parent1017ebe9cb38ae034b0e7c6c449abe2c9b5284fb (diff)
downloadqemu-7d13299d07a9c3c42277207ae7a691f0501a70b2.tar.gz
added translation cache
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@25 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r--Makefile40
-rw-r--r--TODO6
-rwxr-xr-xconfigure240
-rw-r--r--cpu-i386.h1
-rw-r--r--dyngen.c19
-rw-r--r--exec-i386.c213
-rw-r--r--exec-i386.h105
-rw-r--r--linux-user/main.c2
-rw-r--r--linux-user/syscall.c3
-rw-r--r--op-i386.c221
-rw-r--r--tests/Makefile27
-rw-r--r--thunk.h7
-rw-r--r--translate-i386.c21
13 files changed, 651 insertions, 254 deletions
diff --git a/Makefile b/Makefile
index 57d2ba1ba7..0f0b22db72 100644
--- a/Makefile
+++ b/Makefile
@@ -1,43 +1,33 @@
-ARCH=i386
-#ARCH=ppc
-HOST_CC=gcc
+include config.mak
-ifeq ($(ARCH),i386)
-CFLAGS=-Wall -O2 -g -fomit-frame-pointer
+CFLAGS=-Wall -O2 -g
LDFLAGS=-g
LIBS=
-CC=gcc
DEFINES=-DHAVE_BYTESWAP_H
+
+ifeq ($(ARCH),i386)
+CFLAGS+=-fomit-frame-pointer
OP_CFLAGS=$(CFLAGS) -malign-functions=0 -mpreferred-stack-boundary=2
endif
ifeq ($(ARCH),ppc)
-GCC_LIBS_DIR=/usr/netgem/tools/lib/gcc-lib/powerpc-linux/2.95.2
-DIST=/home/fbe/nsv/dist/hw/n6-dtt
-CC=powerpc-linux-gcc -msoft-float
-CFLAGS=-Wall -pipe -O2 -mcpu=405 -mbig -nostdinc -g -I$(GCC_LIBS_DIR)/include -I$(DIST)/include
-LIBS_DIR=$(DIST)/lib
-CRT1=$(LIBS_DIR)/crt1.o
-CRTI=$(LIBS_DIR)/crti.o
-CRTN=$(LIBS_DIR)/crtn.o
-CRTBEGIN=$(GCC_LIBS_DIR)/crtbegin.o
-CRTEND=$(GCC_LIBS_DIR)/crtend.o
-LDFLAGS=-static -g -nostdlib $(CRT1) $(CRTI) $(CRTBEGIN)
-LIBS=-L$(LIBS_DIR) -ltinyc -lgcc $(CRTEND) $(CRTN)
-DEFINES=-Dsocklen_t=int
OP_CFLAGS=$(CFLAGS)
endif
#########################################################
DEFINES+=-D_GNU_SOURCE
-DEFINES+=-DCONFIG_PREFIX=\"/usr/local\"
LDSCRIPT=$(ARCH).ld
LIBS+=-ldl -lm
-VERSION=0.1
+
+# profiling code
+ifdef TARGET_GPROF
+LDFLAGS+=-p
+CFLAGS+=-p
+endif
OBJS= elfload.o main.o thunk.o syscall.o
-OBJS+=translate-i386.o op-i386.o
+OBJS+=translate-i386.o op-i386.o exec-i386.o
# NOTE: the disassembler code is only needed for debugging
OBJS+=i386-dis.o dis-buf.o
SRCS = $(OBJS:.o=.c)
@@ -66,8 +56,12 @@ op-i386.o: op-i386.c opreg_template.h ops_template.h
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
clean:
+ $(MAKE) -C tests clean
rm -f *.o *~ gemu dyngen TAGS
+distclean: clean
+ rm -f config.mak config.h
+
# various test targets
test speed: gemu
make -C tests $@
@@ -82,7 +76,7 @@ TODO elfload.c main.c signal.c thunk.h\
cpu-i386.h gemu.h op-i386.c syscall-i386.h translate-i386.c\
dis-asm.h gen-i386.h op-i386.h syscall.c\
dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\
-i386.ld ppc.ld\
+i386.ld ppc.ld exec-i386.h exec-i386.c configure VERSION \
tests/Makefile\
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\
tests/test-i386-muldiv.h\
diff --git a/TODO b/TODO
index a12c384678..3b04b7dce1 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,8 @@
-- tests
+- optimize translated cache chaining (DLL PLT like system)
+- optimize inverse flags propagation (easy by generating intermediate
+ micro operation array).
- signals
- threads
-- fix printf for doubles (fp87.c bug ?)
- make it self runnable (use same trick as ld.so : include its own relocator and libc)
- fix FPU exceptions (in particular: gen_op_fpush not before mem load)
+- tests
diff --git a/configure b/configure
new file mode 100755
index 0000000000..16252c4dce
--- /dev/null
+++ b/configure
@@ -0,0 +1,240 @@
+#!/bin/sh
+#
+# gemu configure script (c) 2003 Fabrice Bellard
+#
+# set temporary file name
+if test ! -z "$TMPDIR" ; then
+ TMPDIR1="${TMPDIR}"
+elif test ! -z "$TEMPDIR" ; then
+ TMPDIR1="${TEMPDIR}"
+else
+ TMPDIR1="/tmp"
+fi
+
+TMPC="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.c"
+TMPO="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.o"
+TMPS="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.S"
+TMPH="${TMPDIR1}/qemacs-conf-${RANDOM}-$$-${RANDOM}.h"
+
+# default parameters
+prefix="/usr/local"
+cross_prefix=""
+cc="gcc"
+host_cc="gcc"
+ar="ar"
+make="make"
+strip="strip"
+cpu=`uname -m`
+case "$cpu" in
+ i386|i486|i586|i686|i86pc|BePC)
+ cpu="x86"
+ ;;
+ armv4l)
+ cpu="armv4l"
+ ;;
+ alpha)
+ cpu="alpha"
+ ;;
+ "Power Macintosh"|ppc)
+ cpu="powerpc"
+ ;;
+ mips)
+ cpu="mips"
+ ;;
+ *)
+ cpu="unknown"
+ ;;
+esac
+gprof="no"
+bigendian="no"
+
+# OS specific
+targetos=`uname -s`
+case $targetos in
+BeOS)
+prefix="/boot/home/config"
+# helps building libavcodec
+CFLAGS="-O2 -DPIC"
+# no need for libm, but the inet stuff
+# Check for BONE
+if (echo $BEINCLUDES|grep 'headers/be/bone' >/dev/null); then
+extralibs="-lbind -lsocket"
+else
+echo "Not sure building for net_server will succeed... good luck."
+extralibs="-lsocket"
+fi ;;
+BSD/OS)
+extralibs="-lpoll -lgnugetopt -lm"
+make="gmake"
+;;
+*) ;;
+esac
+
+# find source path
+# XXX: we assume an absolute path is given when launching configure,
+# except in './configure' case.
+source_path=${0%configure}
+source_path=${source_path%/}
+source_path_used="yes"
+if test -z "$source_path" -o "$source_path" = "." ; then
+ source_path=`pwd`
+ source_path_used="no"
+fi
+
+for opt do
+ case "$opt" in
+ --prefix=*) prefix=`echo $opt | cut -d '=' -f 2`
+ ;;
+ --source-path=*) source_path=`echo $opt | cut -d '=' -f 2`
+ ;;
+ --cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2`
+ ;;
+ --cc=*) cc=`echo $opt | cut -d '=' -f 2`
+ ;;
+ --make=*) make=`echo $opt | cut -d '=' -f 2`
+ ;;
+ --extra-cflags=*) CFLAGS="${opt#--extra-cflags=}"
+ ;;
+ --extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}"
+ ;;
+ --extra-libs=*) extralibs=${opt#--extra-libs=}
+ ;;
+ --cpu=*) cpu=`echo $opt | cut -d '=' -f 2`
+ ;;
+ --enable-gprof) gprof="yes"
+ ;;
+ esac
+done
+
+# Checking for CFLAGS
+if test -z "$CFLAGS"; then
+ CFLAGS="-O2"
+fi
+
+cc="${cross_prefix}${cc}"
+ar="${cross_prefix}${ar}"
+strip="${cross_prefix}${strip}"
+
+if test -z "$cross_prefix" ; then
+
+# ---
+# big/little endian test
+cat > $TMPC << EOF
+#include <inttypes.h>
+int main(int argc, char ** argv){
+ volatile uint32_t i=0x01234567;
+ return (*((uint8_t*)(&i))) == 0x67;
+}
+EOF
+
+if $cc -o $TMPE $TMPC 2>/dev/null ; then
+$TMPE && bigendian="yes"
+else
+echo big/little test failed
+fi
+
+else
+
+# if cross compiling, cannot launch a program, so make a static guess
+if test "$cpu" = "powerpc" -o "$cpu" = "mips" ; then
+ bigendian="yes"
+fi
+
+fi
+
+if test x"$1" = x"-h" -o x"$1" = x"--help" ; then
+cat << EOF
+
+Usage: configure [options]
+Options: [defaults in brackets after descriptions]
+
+EOF
+echo "Standard options:"
+echo " --help print this message"
+echo " --prefix=PREFIX install in PREFIX [$prefix]"
+echo " for audio/video/image support"
+echo ""
+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 " --make=MAKE use specified make [$make]"
+echo ""
+echo "NOTE: The object files are build at the place where configure is launched"
+exit 1
+fi
+
+echo "Install prefix $prefix"
+echo "Source path $source_path"
+echo "C compiler $cc"
+echo "make $make"
+echo "CPU $cpu"
+echo "Big Endian $bigendian"
+echo "gprof enabled $gprof"
+
+echo "Creating config.mak and config.h"
+
+echo "# Automatically generated by configure - do not modify" > config.mak
+echo "/* Automatically generated by configure - do not modify */" > $TMPH
+
+echo "prefix=$prefix" >> config.mak
+echo "#define CONFIG_GEMU_PREFIX \"$prefix\"" >> $TMPH
+echo "MAKE=$make" >> config.mak
+echo "CC=$cc" >> config.mak
+echo "HOST_CC=$host_cc" >> config.mak
+echo "AR=$ar" >> config.mak
+echo "STRIP=$strip -s -R .comment -R .note" >> config.mak
+echo "CFLAGS=$CFLAGS" >> config.mak
+echo "LDFLAGS=$LDFLAGS" >> config.mak
+if test "$cpu" = "x86" ; then
+ echo "ARCH=i386" >> config.mak
+elif test "$cpu" = "armv4l" ; then
+ echo "ARCH=arm" >> config.mak
+elif test "$cpu" = "powerpc" ; then
+ echo "ARCH=ppc" > config.mak
+elif test "$cpu" = "mips" ; then
+ echo "ARCH=mips" > config.mak
+else
+ echo "Unsupported CPU"
+ exit 1
+fi
+if test "$bigendian" = "yes" ; then
+ echo "WORDS_BIGENDIAN=yes" >> config.mak
+ echo "#define WORDS_BIGENDIAN 1" >> $TMPH
+fi
+if test "$gprof" = "yes" ; then
+ echo "TARGET_GPROF=yes" >> config.mak
+ echo "#define HAVE_GPROF 1" >> $TMPH
+fi
+echo -n "VERSION=" >>config.mak
+head $source_path/VERSION >>config.mak
+echo "" >>config.mak
+echo -n "#define GEMU_VERSION \"" >> $TMPH
+head $source_path/VERSION >> $TMPH
+echo "\"" >> $TMPH
+if test "$network" = "yes" ; then
+ echo "#define CONFIG_NETWORK 1" >> $TMPH
+ echo "CONFIG_NETWORK=yes" >> config.mak
+fi
+
+# build tree in object directory if source path is different from current one
+if test "$source_path_used" = "yes" ; then
+ DIRS="tests"
+ FILES="Makefile tests/Makefile"
+ for dir in $DIRS ; do
+ mkdir -p $dir
+ done
+ for f in $FILES ; do
+ ln -sf $source_path/$f $f
+ done
+fi
+echo "SRC_PATH=$source_path" >> config.mak
+
+diff $TMPH config.h >/dev/null 2>&1
+if test $? -ne 0 ; then
+ mv -f $TMPH config.h
+else
+ echo "config.h is unchanged"
+fi
+
+rm -f $TMPH
diff --git a/cpu-i386.h b/cpu-i386.h
index 4d06d92060..a6464efca4 100644
--- a/cpu-i386.h
+++ b/cpu-i386.h
@@ -244,5 +244,6 @@ void cpu_x86_close(CPUX86State *s);
/* internal functions */
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
int *gen_code_size_ptr, uint8_t *pc_start);
+void cpu_x86_tblocks_init(void);
#endif /* CPU_I386_H */
diff --git a/dyngen.c b/dyngen.c
index f6b102fefa..40a7fc695b 100644
--- a/dyngen.c
+++ b/dyngen.c
@@ -1,3 +1,22 @@
+/*
+ * Generic Dynamic compiler generator
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
diff --git a/exec-i386.c b/exec-i386.c
new file mode 100644
index 0000000000..c067685095
--- /dev/null
+++ b/exec-i386.c
@@ -0,0 +1,213 @@
+/*
+ * i386 emulator main execution loop
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "exec-i386.h"
+
+#define DEBUG_EXEC
+#define DEBUG_FLUSH
+
+/* main execution loop */
+
+/* maximum total translate dcode allocated */
+#define CODE_GEN_BUFFER_SIZE (2048 * 1024)
+//#define CODE_GEN_BUFFER_SIZE (128 * 1024)
+#define CODE_GEN_MAX_SIZE 65536
+#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
+
+/* threshold to flush the translated code buffer */
+#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)
+
+#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64)
+#define CODE_GEN_HASH_BITS 15
+#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)
+typedef struct TranslationBlock {
+ unsigned long pc; /* simulated PC corresponding to this block */
+ uint8_t *tc_ptr; /* pointer to the translated code */
+ struct TranslationBlock *hash_next; /* next matching block */
+} TranslationBlock;
+
+TranslationBlock tbs[CODE_GEN_MAX_BLOCKS];
+TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE];
+int nb_tbs;
+
+uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE];
+uint8_t *code_gen_ptr;
+
+#ifdef DEBUG_EXEC
+static const char *cc_op_str[] = {
+ "DYNAMIC",
+ "EFLAGS",
+ "MUL",
+ "ADDB",
+ "ADDW",
+ "ADDL",
+ "ADCB",
+ "ADCW",
+ "ADCL",
+ "SUBB",
+ "SUBW",
+ "SUBL",
+ "SBBB",
+ "SBBW",
+ "SBBL",
+ "LOGICB",
+ "LOGICW",
+ "LOGICL",
+ "INCB",
+ "INCW",
+ "INCL",
+ "DECB",
+ "DECW",
+ "DECL",
+ "SHLB",
+ "SHLW",
+ "SHLL",
+ "SARB",
+ "SARW",
+ "SARL",
+};
+
+static void cpu_x86_dump_state(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ eflags |= (DF & DIRECTION_FLAG);
+ fprintf(logfile,
+ "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
+ "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
+ "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n",
+ env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
+ env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
+ env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
+ eflags & DIRECTION_FLAG ? 'D' : '-',
+ eflags & CC_O ? 'O' : '-',
+ eflags & CC_S ? 'S' : '-',
+ eflags & CC_Z ? 'Z' : '-',
+ eflags & CC_A ? 'A' : '-',
+ eflags & CC_P ? 'P' : '-',
+ eflags & CC_C ? 'C' : '-'
+ );
+#if 1
+ fprintf(logfile, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
+ (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
+#endif
+}
+
+#endif
+
+void cpu_x86_tblocks_init(void)
+{
+ if (!code_gen_ptr) {
+ code_gen_ptr = code_gen_buffer;
+ }
+}
+
+/* flush all the translation blocks */
+static void tb_flush(void)
+{
+ int i;
+#ifdef DEBUG_FLUSH
+ printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
+ code_gen_ptr - code_gen_buffer,
+ nb_tbs,
+ (code_gen_ptr - code_gen_buffer) / nb_tbs);
+#endif
+ nb_tbs = 0;
+ for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
+ tb_hash[i] = NULL;
+ code_gen_ptr = code_gen_buffer;
+ /* XXX: flush processor icache at this point */
+}
+
+/* find a translation block in the translation cache. If not found,
+ allocate a new one */
+static inline TranslationBlock *tb_find_and_alloc(unsigned long pc)
+{
+ TranslationBlock **ptb, *tb;
+ unsigned int h;
+
+ h = pc & (CODE_GEN_HASH_SIZE - 1);
+ ptb = &tb_hash[h];
+ for(;;) {
+ tb = *ptb;
+ if (!tb)
+ break;
+ if (tb->pc == pc)
+ return tb;
+ ptb = &tb->hash_next;
+ }
+ if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
+ (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
+ tb_flush();
+ tb = &tbs[nb_tbs++];
+ *ptb = tb;
+ tb->pc = pc;
+ tb->tc_ptr = NULL;
+ tb->hash_next = NULL;
+ return tb;
+}
+
+int cpu_x86_exec(CPUX86State *env1)
+{
+ int saved_T0, saved_T1, saved_A0;
+ CPUX86State *saved_env;
+ int code_gen_size, ret;
+ void (*gen_func)(void);
+ TranslationBlock *tb;
+ uint8_t *tc_ptr;
+
+ /* first we save global registers */
+ saved_T0 = T0;
+ saved_T1 = T1;
+ saved_A0 = A0;
+ saved_env = env;
+ env = env1;
+
+ /* prepare setjmp context for exception handling */
+ if (setjmp(env->jmp_env) == 0) {
+ for(;;) {
+#ifdef DEBUG_EXEC
+ if (loglevel) {
+ cpu_x86_dump_state();
+ }
+#endif
+ tb = tb_find_and_alloc((unsigned long)env->pc);
+ tc_ptr = tb->tc_ptr;
+ if (!tb->tc_ptr) {
+ /* if no translated code available, then translate it now */
+ tc_ptr = code_gen_ptr;
+ cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
+ &code_gen_size, (uint8_t *)env->pc);
+ tb->tc_ptr = tc_ptr;
+ code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
+ }
+ /* execute the generated code */
+ gen_func = (void *)tc_ptr;
+ gen_func();
+ }
+ }
+ ret = env->exception_index;
+
+ /* restore global registers */
+ T0 = saved_T0;
+ T1 = saved_T1;
+ A0 = saved_A0;
+ env = saved_env;
+ return ret;
+}
diff --git a/exec-i386.h b/exec-i386.h
new file mode 100644
index 0000000000..62f681bc1a
--- /dev/null
+++ b/exec-i386.h
@@ -0,0 +1,105 @@
+/* i386 execution defines */
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long long int64_t;
+
+#define bswap32(x) \
+({ \
+ uint32_t __x = (x); \
+ ((uint32_t)( \
+ (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+ (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
+ (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
+ (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
+})
+
+#define NULL 0
+#include <fenv.h>
+
+typedef struct FILE FILE;
+extern FILE *logfile;
+extern int loglevel;
+extern int fprintf(FILE *, const char *, ...);
+
+#ifdef __i386__
+register unsigned int T0 asm("ebx");
+register unsigned int T1 asm("esi");
+register unsigned int A0 asm("edi");
+register struct CPUX86State *env asm("ebp");
+#endif
+#ifdef __powerpc__
+register unsigned int T0 asm("r24");
+register unsigned int T1 asm("r25");
+register unsigned int A0 asm("r26");
+register struct CPUX86State *env asm("r27");
+#endif
+#ifdef __arm__
+register unsigned int T0 asm("r4");
+register unsigned int T1 asm("r5");
+register unsigned int A0 asm("r6");
+register struct CPUX86State *env asm("r7");
+#endif
+#ifdef __mips__
+register unsigned int T0 asm("s0");
+register unsigned int T1 asm("s1");
+register unsigned int A0 asm("s2");
+register struct CPUX86State *env asm("s3");
+#endif
+#ifdef __sparc__
+register unsigned int T0 asm("l0");
+register unsigned int T1 asm("l1");
+register unsigned int A0 asm("l2");
+register struct CPUX86State *env asm("l3");
+#endif
+
+/* force GCC to generate only one epilog at the end of the function */
+#define FORCE_RET() asm volatile ("");
+
+#ifndef OPPROTO
+#define OPPROTO
+#endif
+
+#define xglue(x, y) x ## y
+#define glue(x, y) xglue(x, y)
+
+#define EAX (env->regs[R_EAX])
+#define ECX (env->regs[R_ECX])
+#define EDX (env->regs[R_EDX])
+#define EBX (env->regs[R_EBX])
+#define ESP (env->regs[R_ESP])
+#define EBP (env->regs[R_EBP])
+#define ESI (env->regs[R_ESI])
+#define EDI (env->regs[R_EDI])
+#define PC (env->pc)
+#define DF (env->df)
+
+#define CC_SRC (env->cc_src)
+#define CC_DST (env->cc_dst)
+#define CC_OP (env->cc_op)
+
+/* float macros */
+#define FT0 (env->ft0)
+#define ST0 (env->fpregs[env->fpstt])
+#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7])
+#define ST1 ST(1)
+
+extern int __op_param1, __op_param2, __op_param3;
+#define PARAM1 ((long)(&__op_param1))
+#define PARAM2 ((long)(&__op_param2))
+#define PARAM3 ((long)(&__op_param3))
+
+#include "cpu-i386.h"
+
+typedef struct CCTable {
+ int (*compute_all)(void); /* return all the flags */
+ int (*compute_c)(void); /* return the C flag */
+} CCTable;
+
+extern CCTable cc_table[];
diff --git a/linux-user/main.c b/linux-user/main.c
index 356d980f04..9927b8256a 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -87,7 +87,7 @@ int cpu_x86_inl(int addr)
void usage(void)
{
- printf("gemu version 0.1, Copyright (c) 2003 Fabrice Bellard\n"
+ printf("gemu version" GEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
"usage: gemu [-d] program [arguments...]\n"
"Linux x86 emulator\n"
);
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f800fa219e..ac40cf19ef 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -628,6 +628,9 @@ long do_syscall(int num, long arg1, long arg2, long arg3,
#endif
switch(num) {
case TARGET_NR_exit:
+#ifdef HAVE_GPROF
+ _mcleanup();
+#endif
_exit(arg1);
ret = 0; /* avoid warning */
break;
diff --git a/op-i386.c b/op-i386.c
index 2cca6a6722..6bd9de0155 100644
--- a/op-i386.c
+++ b/op-i386.c
@@ -1,109 +1,25 @@
-#define DEBUG_EXEC
-
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long uint64_t;
-
-typedef signed char int8_t;
-typedef signed short int16_t;
-typedef signed int int32_t;
-typedef signed long long int64_t;
-
-#define bswap32(x) \
-({ \
- uint32_t __x = (x); \
- ((uint32_t)( \
- (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
- (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
- (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
- (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
-})
-
-#define NULL 0
-#include <fenv.h>
-
-typedef struct FILE FILE;
-extern FILE *logfile;
-extern int loglevel;
-extern int fprintf(FILE *, const char *, ...);
-
-#ifdef __i386__
-register unsigned int T0 asm("ebx");
-register unsigned int T1 asm("esi");
-register unsigned int A0 asm("edi");
-register struct CPUX86State *env asm("ebp");
-#endif
-#ifdef __powerpc__
-register unsigned int T0 asm("r24");
-register unsigned int T1 asm("r25");
-register unsigned int A0 asm("r26");
-register struct CPUX86State *env asm("r27");
-#endif
-#ifdef __arm__
-register unsigned int T0 asm("r4");
-register unsigned int T1 asm("r5");
-register unsigned int A0 asm("r6");
-register struct CPUX86State *env asm("r7");
-#endif
-#ifdef __mips__
-register unsigned int T0 asm("s0");
-register unsigned int T1 asm("s1");
-register unsigned int A0 asm("s2");
-register struct CPUX86State *env asm("s3");
-#endif
-#ifdef __sparc__
-register unsigned int T0 asm("l0");
-register unsigned int T1 asm("l1");
-register unsigned int A0 asm("l2");
-register struct CPUX86State *env asm("l3");
-#endif
-
-/* force GCC to generate only one epilog at the end of the function */
-#define FORCE_RET() asm volatile ("");
-
-#ifndef OPPROTO
-#define OPPROTO
-#endif
-
-#define xglue(x, y) x ## y
-#define glue(x, y) xglue(x, y)
-
-#define EAX (env->regs[R_EAX])
-#define ECX (env->regs[R_ECX])
-#define EDX (env->regs[R_EDX])
-#define EBX (env->regs[R_EBX])
-#define ESP (env->regs[R_ESP])
-#define EBP (env->regs[R_EBP])
-#define ESI (env->regs[R_ESI])
-#define EDI (env->regs[R_EDI])
-#define PC (env->pc)
-#define DF (env->df)
-
-#define CC_SRC (env->cc_src)
-#define CC_DST (env->cc_dst)
-#define CC_OP (env->cc_op)
-
-/* float macros */
-#define FT0 (env->ft0)
-#define ST0 (env->fpregs[env->fpstt])
-#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7])
-#define ST1 ST(1)
-
-extern int __op_param1, __op_param2, __op_param3;
-#define PARAM1 ((long)(&__op_param1))
-#define PARAM2 ((long)(&__op_param2))
-#define PARAM3 ((long)(&__op_param3))
-
-#include "cpu-i386.h"
-
-typedef struct CCTable {
- int (*compute_all)(void); /* return all the flags */
- int (*compute_c)(void); /* return the C flag */
-} CCTable;
+/*
+ * i386 micro operations
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include "exec-i386.h"
/* NOTE: data are not static to force relocation generation by GCC */
-extern CCTable cc_table[];
uint8_t parity_table[256] = {
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
@@ -1878,100 +1794,3 @@ void OPPROTO op_fldcw_A0(void)
fesetround(rnd_type);
}
-/* main execution loop */
-uint8_t code_gen_buffer[65536];
-
-#ifdef DEBUG_EXEC
-static const char *cc_op_str[] = {
- "DYNAMIC",
- "EFLAGS",
- "MUL",
- "ADDB",
- "ADDW",
- "ADDL",
- "ADCB",
- "ADCW",
- "ADCL",
- "SUBB",
- "SUBW",
- "SUBL",
- "SBBB",
- "SBBW",
- "SBBL",
- "LOGICB",
- "LOGICW",
- "LOGICL",
- "INCB",
- "INCW",
- "INCL",
- "DECB",
- "DECW",
- "DECL",
- "SHLB",
- "SHLW",
- "SHLL",
- "SARB",
- "SARW",
- "SARL",
-};
-#endif
-
-int cpu_x86_exec(CPUX86State *env1)
-{
- int saved_T0, saved_T1, saved_A0;
- CPUX86State *saved_env;
- int code_gen_size, ret;
- void (*gen_func)(void);
-
- /* first we save global registers */
- saved_T0 = T0;
- saved_T1 = T1;
- saved_A0 = A0;
- saved_env = env;
- env = env1;
-
- /* prepare setjmp context for exception handling */
- if (setjmp(env->jmp_env) == 0) {
- for(;;) {
-#ifdef DEBUG_EXEC
- if (loglevel) {
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- eflags |= (DF & DIRECTION_FLAG);
- fprintf(logfile,
- "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n"
- "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n"
- "CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n",
- env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX],
- env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP],
- env->cc_src, env->cc_dst, cc_op_str[env->cc_op],
- eflags & DIRECTION_FLAG ? 'D' : '-',
- eflags & CC_O ? 'O' : '-',
- eflags & CC_S ? 'S' : '-',
- eflags & CC_Z ? 'Z' : '-',
- eflags & CC_A ? 'A' : '-',
- eflags & CC_P ? 'P' : '-',
- eflags & CC_C ? 'C' : '-'
- );
-#if 1
- fprintf(logfile, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
- (double)ST0, (double)ST1, (double)ST(2), (double)ST(3));
-#endif
- }
-#endif
- cpu_x86_gen_code(code_gen_buffer, sizeof(code_gen_buffer),
- &code_gen_size, (uint8_t *)env->pc);
- /* execute the generated code */
- gen_func = (void *)code_gen_buffer;
- gen_func();
- }
- }
- ret = env->exception_index;
-
- /* restore global registers */
- T0 = saved_T0;
- T1 = saved_T1;
- A0 = saved_A0;
- env = saved_env;
- return ret;
-}
diff --git a/tests/Makefile b/tests/Makefile
index 5fc813c236..c7d1154c00 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,9 +1,11 @@
-CC=gcc
+include ../config.mak
+
CFLAGS=-Wall -O2 -g
LDFLAGS=
+ifeq ($(ARCH),i386)
TESTS=hello test2 sha1 test-i386
-TESTS+=op-i386.o #op-i386.o op-ppc.o op-arm.o op-mips.o op-sparc.o
+endif
GEMU=../gemu
@@ -24,22 +26,6 @@ test: test-i386
$(GEMU) test-i386 > test-i386.out
@if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi
-# dyngen tests
-op-i386.o: op.c
- gcc $(CFLAGS) -c -o $@ $<
-
-op-ppc.o: op.c
- powerpc-linux-gcc $(CFLAGS) -c -o $@ $<
-
-op-arm.o: op.c
- arm-linux-gcc $(CFLAGS) -c -o $@ $<
-
-op-mips.o: op.c
- mips-linux-gcc $(CFLAGS) -mno-abicalls -c -o $@ $<
-
-op-sparc.o: op.c
- sparc-linux-gcc $(CFLAGS) -mflat -c -o $@ $<
-
# speed test
sha1: sha1.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
@@ -48,6 +34,5 @@ speed: sha1
time ./sha1
time $(GEMU) sha1
-# interpreter test
-interp: interp.c interploop.c
- $(CC) $(CFLAGS) -fomit-frame-pointer $(LDFLAGS) -o $@ $^
+clean:
+ rm -f *~ *.o $(TESTS)
diff --git a/thunk.h b/thunk.h
index 5e5d9dd18d..a7338ad76a 100644
--- a/thunk.h
+++ b/thunk.h
@@ -2,7 +2,7 @@
#define THUNK_H
#include <inttypes.h>
-#include <endian.h>
+#include "config.h"
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
@@ -42,11 +42,6 @@
#endif
-#undef WORDS_BIGENDIAN
-#if __BYTE_ORDER == __BIG_ENDIAN
-#define WORDS_BIGENDIAN
-#endif
-
#ifdef WORDS_BIGENDIAN
#define BSWAP_NEEDED
#endif
diff --git a/translate-i386.c b/translate-i386.c
index d13d5d7449..ad46e1373e 100644
--- a/translate-i386.c
+++ b/translate-i386.c
@@ -1,3 +1,22 @@
+/*
+ * i386 translation
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
@@ -2591,6 +2610,8 @@ CPUX86State *cpu_x86_init(void)
CPUX86State *env;
int i;
+ cpu_x86_tblocks_init();
+
env = malloc(sizeof(CPUX86State));
if (!env)
return NULL;