From 7d13299d07a9c3c42277207ae7a691f0501a70b2 Mon Sep 17 00:00:00 2001 From: bellard Date: Thu, 6 Mar 2003 23:23:54 +0000 Subject: [PATCH] added translation cache git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@25 c046a42c-6fe2-441c-8c8c-71466251a162 --- Makefile | 40 +++----- TODO | 6 +- configure | 240 +++++++++++++++++++++++++++++++++++++++++++ cpu-i386.h | 1 + dyngen.c | 19 ++++ exec-i386.c | 213 ++++++++++++++++++++++++++++++++++++++ exec-i386.h | 105 +++++++++++++++++++ linux-user/main.c | 2 +- linux-user/syscall.c | 3 + op-i386.c | 221 ++++----------------------------------- tests/Makefile | 27 ++--- thunk.h | 7 +- translate-i386.c | 21 ++++ 13 files changed, 651 insertions(+), 254 deletions(-) create mode 100755 configure create mode 100644 exec-i386.c create mode 100644 exec-i386.h 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 +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 #include #include 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 + +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 - -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 -#include +#include "config.h" #ifdef HAVE_BYTESWAP_H #include @@ -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 #include #include @@ -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;