added translation cache

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@25 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2003-03-06 23:23:54 +00:00
parent 1017ebe9cb
commit 7d13299d07
13 changed files with 651 additions and 254 deletions

View File

@ -1,43 +1,33 @@
ARCH=i386 include config.mak
#ARCH=ppc
HOST_CC=gcc
ifeq ($(ARCH),i386) CFLAGS=-Wall -O2 -g
CFLAGS=-Wall -O2 -g -fomit-frame-pointer
LDFLAGS=-g LDFLAGS=-g
LIBS= LIBS=
CC=gcc
DEFINES=-DHAVE_BYTESWAP_H DEFINES=-DHAVE_BYTESWAP_H
ifeq ($(ARCH),i386)
CFLAGS+=-fomit-frame-pointer
OP_CFLAGS=$(CFLAGS) -malign-functions=0 -mpreferred-stack-boundary=2 OP_CFLAGS=$(CFLAGS) -malign-functions=0 -mpreferred-stack-boundary=2
endif endif
ifeq ($(ARCH),ppc) 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) OP_CFLAGS=$(CFLAGS)
endif endif
######################################################### #########################################################
DEFINES+=-D_GNU_SOURCE DEFINES+=-D_GNU_SOURCE
DEFINES+=-DCONFIG_PREFIX=\"/usr/local\"
LDSCRIPT=$(ARCH).ld LDSCRIPT=$(ARCH).ld
LIBS+=-ldl -lm 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= 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 # NOTE: the disassembler code is only needed for debugging
OBJS+=i386-dis.o dis-buf.o OBJS+=i386-dis.o dis-buf.o
SRCS = $(OBJS:.o=.c) 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 $@ $< $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
clean: clean:
$(MAKE) -C tests clean
rm -f *.o *~ gemu dyngen TAGS rm -f *.o *~ gemu dyngen TAGS
distclean: clean
rm -f config.mak config.h
# various test targets # various test targets
test speed: gemu test speed: gemu
make -C tests $@ 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\ 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-asm.h gen-i386.h op-i386.h syscall.c\
dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\ 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/Makefile\
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\ tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\
tests/test-i386-muldiv.h\ tests/test-i386-muldiv.h\

6
TODO
View File

@ -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 - signals
- threads - threads
- fix printf for doubles (fp87.c bug ?)
- make it self runnable (use same trick as ld.so : include its own relocator and libc) - 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) - fix FPU exceptions (in particular: gen_op_fpush not before mem load)
- tests

240
configure vendored Executable file
View File

@ -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

View File

@ -244,5 +244,6 @@ void cpu_x86_close(CPUX86State *s);
/* internal functions */ /* internal functions */
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
int *gen_code_size_ptr, uint8_t *pc_start); int *gen_code_size_ptr, uint8_t *pc_start);
void cpu_x86_tblocks_init(void);
#endif /* CPU_I386_H */ #endif /* CPU_I386_H */

View File

@ -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 <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>

213
exec-i386.c Normal file
View File

@ -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;
}

105
exec-i386.h Normal file
View File

@ -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[];

View File

@ -87,7 +87,7 @@ int cpu_x86_inl(int addr)
void usage(void) 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" "usage: gemu [-d] program [arguments...]\n"
"Linux x86 emulator\n" "Linux x86 emulator\n"
); );

View File

@ -628,6 +628,9 @@ long do_syscall(int num, long arg1, long arg2, long arg3,
#endif #endif
switch(num) { switch(num) {
case TARGET_NR_exit: case TARGET_NR_exit:
#ifdef HAVE_GPROF
_mcleanup();
#endif
_exit(arg1); _exit(arg1);
ret = 0; /* avoid warning */ ret = 0; /* avoid warning */
break; break;

221
op-i386.c
View File

@ -1,109 +1,25 @@
#define DEBUG_EXEC /*
* i386 micro operations
typedef unsigned char uint8_t; *
typedef unsigned short uint16_t; * Copyright (c) 2003 Fabrice Bellard
typedef unsigned int uint32_t; *
typedef unsigned long long uint64_t; * 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
typedef signed char int8_t; * the Free Software Foundation; either version 2 of the License, or
typedef signed short int16_t; * (at your option) any later version.
typedef signed int int32_t; *
typedef signed long long int64_t; * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
#define bswap32(x) \ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
({ \ * GNU General Public License for more details.
uint32_t __x = (x); \ *
((uint32_t)( \ * You should have received a copy of the GNU General Public License
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ * along with this program; if not, write to the Free Software
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ */
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ #include "exec-i386.h"
})
#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;
/* NOTE: data are not static to force relocation generation by GCC */ /* NOTE: data are not static to force relocation generation by GCC */
extern CCTable cc_table[];
uint8_t parity_table[256] = { uint8_t parity_table[256] = {
CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, 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); 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;
}

View File

@ -1,9 +1,11 @@
CC=gcc include ../config.mak
CFLAGS=-Wall -O2 -g CFLAGS=-Wall -O2 -g
LDFLAGS= LDFLAGS=
ifeq ($(ARCH),i386)
TESTS=hello test2 sha1 test-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 GEMU=../gemu
@ -24,22 +26,6 @@ test: test-i386
$(GEMU) test-i386 > test-i386.out $(GEMU) test-i386 > test-i386.out
@if diff -u test-i386.ref test-i386.out ; then echo "Auto Test OK"; fi @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 # speed test
sha1: sha1.c sha1: sha1.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
@ -48,6 +34,5 @@ speed: sha1
time ./sha1 time ./sha1
time $(GEMU) sha1 time $(GEMU) sha1
# interpreter test clean:
interp: interp.c interploop.c rm -f *~ *.o $(TESTS)
$(CC) $(CFLAGS) -fomit-frame-pointer $(LDFLAGS) -o $@ $^

View File

@ -2,7 +2,7 @@
#define THUNK_H #define THUNK_H
#include <inttypes.h> #include <inttypes.h>
#include <endian.h> #include "config.h"
#ifdef HAVE_BYTESWAP_H #ifdef HAVE_BYTESWAP_H
#include <byteswap.h> #include <byteswap.h>
@ -42,11 +42,6 @@
#endif #endif
#undef WORDS_BIGENDIAN
#if __BYTE_ORDER == __BIG_ENDIAN
#define WORDS_BIGENDIAN
#endif
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
#define BSWAP_NEEDED #define BSWAP_NEEDED
#endif #endif

View File

@ -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 <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -2591,6 +2610,8 @@ CPUX86State *cpu_x86_init(void)
CPUX86State *env; CPUX86State *env;
int i; int i;
cpu_x86_tblocks_init();
env = malloc(sizeof(CPUX86State)); env = malloc(sizeof(CPUX86State));
if (!env) if (!env)
return NULL; return NULL;