use the TCG code generator
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3944 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
c896fe29d6
commit
57fec1fee9
5
LICENSE
5
LICENSE
@ -10,6 +10,9 @@ In particular, the QEMU virtual CPU core library (libqemu.a) is
|
||||
released under the GNU Lesser General Public License. Many hardware
|
||||
device emulation sources are released under the BSD license.
|
||||
|
||||
3) QEMU is a trademark of Fabrice Bellard.
|
||||
3) The Tiny Code Generator (TCG) is released under the BSD license
|
||||
(see license headers in files).
|
||||
|
||||
4) QEMU is a trademark of Fabrice Bellard.
|
||||
|
||||
Fabrice Bellard.
|
@ -172,8 +172,11 @@ all: $(PROGS)
|
||||
|
||||
#########################################################
|
||||
# cpu emulator library
|
||||
LIBOBJS=exec.o kqemu.o translate-op.o translate-all.o cpu-exec.o\
|
||||
LIBOBJS=exec.o kqemu.o translate-all.o cpu-exec.o\
|
||||
translate.o op.o host-utils.o
|
||||
# TCG code generator
|
||||
LIBOBJS+= tcg/tcg.o tcg/tcg-dyngen.o tcg/tcg-runtime.o
|
||||
CPPFLAGS+=-I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/$(ARCH)
|
||||
ifdef CONFIG_SOFTFLOAT
|
||||
LIBOBJS+=fpu/softfloat.o
|
||||
else
|
||||
@ -268,16 +271,16 @@ libqemu.a: $(LIBOBJS)
|
||||
rm -f $@
|
||||
$(AR) rcs $@ $(LIBOBJS)
|
||||
|
||||
translate.o: translate.c gen-op.h opc.h cpu.h
|
||||
translate.o: translate.c gen-op.h dyngen-opc.h cpu.h
|
||||
|
||||
translate-all.o: translate-all.c opc.h cpu.h
|
||||
translate-all.o: translate-all.c dyngen-opc.h cpu.h
|
||||
|
||||
translate-op.o: translate-all.c op.h opc.h cpu.h
|
||||
tcg/tcg.o: op.h dyngen-opc.h cpu.h
|
||||
|
||||
op.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -o $@ $<
|
||||
|
||||
opc.h: op.o $(DYNGEN)
|
||||
dyngen-opc.h: op.o $(DYNGEN)
|
||||
$(DYNGEN) -c -o $@ $<
|
||||
|
||||
gen-op.h: op.o $(DYNGEN)
|
||||
@ -648,8 +651,8 @@ endif # !CONFIG_USER_ONLY
|
||||
$(CC) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o fpu/*.o
|
||||
rm -f *.d */*.d
|
||||
rm -f *.o *.a *~ $(PROGS) gen-op.h dyngen-opc.h op.h nwfpe/*.o fpu/*.o
|
||||
rm -f *.d */*.d tcg/*.o
|
||||
|
||||
install: all
|
||||
ifneq ($(PROGS),)
|
||||
|
1
configure
vendored
1
configure
vendored
@ -1051,6 +1051,7 @@ test -f $config_h && mv $config_h ${config_h}~
|
||||
|
||||
mkdir -p $target_dir
|
||||
mkdir -p $target_dir/fpu
|
||||
mkdir -p $target_dir/tcg
|
||||
if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" ; then
|
||||
mkdir -p $target_dir/nwfpe
|
||||
fi
|
||||
|
12
cpu-all.h
12
cpu-all.h
@ -1048,6 +1048,18 @@ extern int64_t kqemu_ret_int_count;
|
||||
extern int64_t kqemu_ret_excp_count;
|
||||
extern int64_t kqemu_ret_intr_count;
|
||||
|
||||
extern int64_t dyngen_tb_count1;
|
||||
extern int64_t dyngen_tb_count;
|
||||
extern int64_t dyngen_op_count;
|
||||
extern int64_t dyngen_old_op_count;
|
||||
extern int64_t dyngen_tcg_del_op_count;
|
||||
extern int dyngen_op_count_max;
|
||||
extern int64_t dyngen_code_in_len;
|
||||
extern int64_t dyngen_code_out_len;
|
||||
extern int64_t dyngen_interm_time;
|
||||
extern int64_t dyngen_code_time;
|
||||
extern int64_t dyngen_restore_count;
|
||||
extern int64_t dyngen_restore_time;
|
||||
#endif
|
||||
|
||||
#endif /* CPU_ALL_H */
|
||||
|
@ -145,6 +145,7 @@ typedef struct CPUTLBEntry {
|
||||
/* The meaning of the MMU modes is defined in the target code. */ \
|
||||
CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \
|
||||
struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \
|
||||
long temp_buf[128]; /* buffer for temporaries in the code generator */ \
|
||||
\
|
||||
/* from this point: preserved by CPU reset */ \
|
||||
/* ice debug support */ \
|
||||
|
@ -354,7 +354,7 @@ int cpu_exec(CPUState *env1)
|
||||
#endif
|
||||
#endif
|
||||
int ret, interrupt_request;
|
||||
void (*gen_func)(void);
|
||||
long (*gen_func)(void);
|
||||
TranslationBlock *tb;
|
||||
uint8_t *tc_ptr;
|
||||
|
||||
@ -736,7 +736,7 @@ int cpu_exec(CPUState *env1)
|
||||
fp.gp = code_gen_buffer + 2 * (1 << 20);
|
||||
(*(void (*)(void)) &fp)();
|
||||
#else
|
||||
gen_func();
|
||||
T0 = gen_func();
|
||||
#endif
|
||||
env->current_tb = NULL;
|
||||
/* reset soft MMU for next block (it can currently
|
||||
|
@ -1,9 +0,0 @@
|
||||
static inline int gen_new_label(void)
|
||||
{
|
||||
return nb_gen_labels++;
|
||||
}
|
||||
|
||||
static inline void gen_set_label(int n)
|
||||
{
|
||||
gen_labels[n] = gen_opc_ptr - gen_opc_buf;
|
||||
}
|
170
dyngen.c
170
dyngen.c
@ -1212,14 +1212,16 @@ int load_object(const char *filename)
|
||||
|
||||
#endif /* CONFIG_FORMAT_MACH */
|
||||
|
||||
void get_reloc_expr(char *name, int name_size, const char *sym_name)
|
||||
/* return true if the expression is a label reference */
|
||||
int get_reloc_expr(char *name, int name_size, const char *sym_name)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
if (strstart(sym_name, "__op_param", &p)) {
|
||||
snprintf(name, name_size, "param%s", p);
|
||||
} else if (strstart(sym_name, "__op_gen_label", &p)) {
|
||||
snprintf(name, name_size, "gen_labels[param%s]", p);
|
||||
snprintf(name, name_size, "param%s", p);
|
||||
return 1;
|
||||
} else {
|
||||
#ifdef HOST_SPARC
|
||||
if (sym_name[0] == '.')
|
||||
@ -1230,6 +1232,7 @@ void get_reloc_expr(char *name, int name_size, const char *sym_name)
|
||||
#endif
|
||||
snprintf(name, name_size, "(long)(&%s)", sym_name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HOST_IA64
|
||||
@ -1846,7 +1849,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
#if defined(HOST_I386)
|
||||
{
|
||||
char relname[256];
|
||||
int type;
|
||||
int type, is_label;
|
||||
int addend;
|
||||
int reloc_offset;
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
@ -1868,21 +1871,33 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
continue;
|
||||
}
|
||||
|
||||
get_reloc_expr(relname, sizeof(relname), sym_name);
|
||||
is_label = get_reloc_expr(relname, sizeof(relname), sym_name);
|
||||
addend = get32((uint32_t *)(text + rel->r_offset));
|
||||
#ifdef CONFIG_FORMAT_ELF
|
||||
type = ELF32_R_TYPE(rel->r_info);
|
||||
switch(type) {
|
||||
case R_386_32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
|
||||
reloc_offset, relname, addend);
|
||||
break;
|
||||
case R_386_PC32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
|
||||
reloc_offset, relname, reloc_offset, addend);
|
||||
break;
|
||||
default:
|
||||
error("unsupported i386 relocation (%d)", type);
|
||||
if (is_label) {
|
||||
switch(type) {
|
||||
case R_386_32:
|
||||
case R_386_PC32:
|
||||
fprintf(outfile, " tcg_out_reloc(s, gen_code_ptr + %d, %d, %s, %d);\n",
|
||||
reloc_offset, type, relname, addend);
|
||||
break;
|
||||
default:
|
||||
error("unsupported i386 relocation (%d)", type);
|
||||
}
|
||||
} else {
|
||||
switch(type) {
|
||||
case R_386_32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
|
||||
reloc_offset, relname, addend);
|
||||
break;
|
||||
case R_386_PC32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
|
||||
reloc_offset, relname, reloc_offset, addend);
|
||||
break;
|
||||
default:
|
||||
error("unsupported i386 relocation (%d)", type);
|
||||
}
|
||||
}
|
||||
#elif defined(CONFIG_FORMAT_COFF)
|
||||
{
|
||||
@ -1920,32 +1935,45 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
||||
#elif defined(HOST_X86_64)
|
||||
{
|
||||
char relname[256];
|
||||
int type;
|
||||
int type, is_label;
|
||||
int addend;
|
||||
int reloc_offset;
|
||||
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
|
||||
if (rel->r_offset >= start_offset &&
|
||||
rel->r_offset < start_offset + copy_size) {
|
||||
sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
|
||||
get_reloc_expr(relname, sizeof(relname), sym_name);
|
||||
is_label = get_reloc_expr(relname, sizeof(relname), sym_name);
|
||||
type = ELF32_R_TYPE(rel->r_info);
|
||||
addend = rel->r_addend;
|
||||
reloc_offset = rel->r_offset - start_offset;
|
||||
switch(type) {
|
||||
case R_X86_64_32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n",
|
||||
reloc_offset, relname, addend);
|
||||
break;
|
||||
case R_X86_64_32S:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n",
|
||||
reloc_offset, relname, addend);
|
||||
break;
|
||||
case R_X86_64_PC32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
|
||||
reloc_offset, relname, reloc_offset, addend);
|
||||
break;
|
||||
default:
|
||||
error("unsupported X86_64 relocation (%d)", type);
|
||||
if (is_label) {
|
||||
switch(type) {
|
||||
case R_X86_64_32:
|
||||
case R_X86_64_32S:
|
||||
case R_X86_64_PC32:
|
||||
fprintf(outfile, " tcg_out_reloc(s, gen_code_ptr + %d, %d, %s, %d);\n",
|
||||
reloc_offset, type, relname, addend);
|
||||
break;
|
||||
default:
|
||||
error("unsupported X86_64 relocation (%d)", type);
|
||||
}
|
||||
} else {
|
||||
switch(type) {
|
||||
case R_X86_64_32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n",
|
||||
reloc_offset, relname, addend);
|
||||
break;
|
||||
case R_X86_64_32S:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n",
|
||||
reloc_offset, relname, addend);
|
||||
break;
|
||||
case R_X86_64_PC32:
|
||||
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
|
||||
reloc_offset, relname, reloc_offset, addend);
|
||||
break;
|
||||
default:
|
||||
error("unsupported X86_64 relocation (%d)", type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2639,11 +2667,6 @@ int gen_file(FILE *outfile, int out_type)
|
||||
EXE_SYM *sym;
|
||||
|
||||
if (out_type == OUT_INDEX_OP) {
|
||||
fprintf(outfile, "DEF(end, 0, 0)\n");
|
||||
fprintf(outfile, "DEF(nop, 0, 0)\n");
|
||||
fprintf(outfile, "DEF(nop1, 1, 0)\n");
|
||||
fprintf(outfile, "DEF(nop2, 2, 0)\n");
|
||||
fprintf(outfile, "DEF(nop3, 3, 0)\n");
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
const char *name;
|
||||
name = get_sym_name(sym);
|
||||
@ -2653,7 +2676,6 @@ int gen_file(FILE *outfile, int out_type)
|
||||
}
|
||||
} else if (out_type == OUT_GEN_OP) {
|
||||
/* generate gen_xxx functions */
|
||||
fprintf(outfile, "#include \"dyngen-op.h\"\n");
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
const char *name;
|
||||
name = get_sym_name(sym);
|
||||
@ -2670,6 +2692,7 @@ int gen_file(FILE *outfile, int out_type)
|
||||
/* generate big code generation switch */
|
||||
|
||||
#ifdef HOST_ARM
|
||||
#error broken
|
||||
/* We need to know the size of all the ops so we can figure out when
|
||||
to emit constant pools. This must be consistent with opc.h. */
|
||||
fprintf(outfile,
|
||||
@ -2690,16 +2713,8 @@ fprintf(outfile,
|
||||
"};\n");
|
||||
#endif
|
||||
|
||||
fprintf(outfile,
|
||||
"int dyngen_code(uint8_t *gen_code_buf,\n"
|
||||
" uint16_t *label_offsets, uint16_t *jmp_offsets,\n"
|
||||
" const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels)\n"
|
||||
"{\n"
|
||||
" uint8_t *gen_code_ptr;\n"
|
||||
" const uint16_t *opc_ptr;\n"
|
||||
" const uint32_t *opparam_ptr;\n");
|
||||
|
||||
#ifdef HOST_ARM
|
||||
#error broken
|
||||
/* Arm is tricky because it uses constant pools for loading immediate values.
|
||||
We assume (and require) each function is code followed by a constant pool.
|
||||
All the ops are small so this should be ok. For each op we figure
|
||||
@ -2732,6 +2747,7 @@ fprintf(outfile,
|
||||
" uint8_t *arm_pool_ptr = gen_code_buf + 0x1000000;\n");
|
||||
#endif
|
||||
#ifdef HOST_IA64
|
||||
#error broken
|
||||
{
|
||||
long addend, not_first = 0;
|
||||
unsigned long sym_idx;
|
||||
@ -2789,18 +2805,8 @@ fprintf(outfile,
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf(outfile,
|
||||
"\n"
|
||||
" gen_code_ptr = gen_code_buf;\n"
|
||||
" opc_ptr = opc_buf;\n"
|
||||
" opparam_ptr = opparam_buf;\n");
|
||||
|
||||
/* Generate prologue, if needed. */
|
||||
|
||||
fprintf(outfile,
|
||||
" for(;;) {\n");
|
||||
|
||||
#ifdef HOST_ARM
|
||||
#error broken
|
||||
/* Generate constant pool if needed */
|
||||
fprintf(outfile,
|
||||
" if (gen_code_ptr + arm_opc_size[*opc_ptr] >= arm_pool_ptr) {\n"
|
||||
@ -2813,9 +2819,6 @@ fprintf(outfile,
|
||||
" }\n");
|
||||
#endif
|
||||
|
||||
fprintf(outfile,
|
||||
" switch(*opc_ptr++) {\n");
|
||||
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
const char *name;
|
||||
name = get_sym_name(sym);
|
||||
@ -2831,51 +2834,6 @@ fprintf(outfile,
|
||||
gen_code(name, sym->st_value, sym->st_size, outfile, 1);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(outfile,
|
||||
" case INDEX_op_nop:\n"
|
||||
" break;\n"
|
||||
" case INDEX_op_nop1:\n"
|
||||
" opparam_ptr++;\n"
|
||||
" break;\n"
|
||||
" case INDEX_op_nop2:\n"
|
||||
" opparam_ptr += 2;\n"
|
||||
" break;\n"
|
||||
" case INDEX_op_nop3:\n"
|
||||
" opparam_ptr += 3;\n"
|
||||
" break;\n"
|
||||
" default:\n"
|
||||
" goto the_end;\n"
|
||||
" }\n");
|
||||
|
||||
|
||||
fprintf(outfile,
|
||||
" }\n"
|
||||
" the_end:\n"
|
||||
);
|
||||
#ifdef HOST_IA64
|
||||
fprintf(outfile,
|
||||
" {\n"
|
||||
" extern char code_gen_buffer[];\n"
|
||||
" ia64_apply_fixes(&gen_code_ptr, ltoff_fixes, "
|
||||
"(uint64_t) code_gen_buffer + 2*(1<<20), plt_fixes,\n\t\t\t"
|
||||
"sizeof(plt_target)/sizeof(plt_target[0]),\n\t\t\t"
|
||||
"plt_target, plt_offset);\n }\n");
|
||||
#endif
|
||||
|
||||
/* generate some code patching */
|
||||
#ifdef HOST_ARM
|
||||
fprintf(outfile,
|
||||
"if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n"
|
||||
" gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, "
|
||||
"arm_ldr_ptr, arm_data_ptr, arm_data_table + ARM_LDR_TABLE_SIZE, 0);\n");
|
||||
#endif
|
||||
/* flush instruction cache */
|
||||
fprintf(outfile, "flush_icache_range((unsigned long)gen_code_buf, (unsigned long)gen_code_ptr);\n");
|
||||
|
||||
fprintf(outfile, "return gen_code_ptr - gen_code_buf;\n");
|
||||
fprintf(outfile, "}\n\n");
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
449
dyngen.h
449
dyngen.h
@ -1,449 +0,0 @@
|
||||
/*
|
||||
* dyngen helpers
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
int __op_param1, __op_param2, __op_param3;
|
||||
#if defined(__sparc__) || defined(__arm__)
|
||||
void __op_gen_label1(){}
|
||||
void __op_gen_label2(){}
|
||||
void __op_gen_label3(){}
|
||||
#else
|
||||
int __op_gen_label1, __op_gen_label2, __op_gen_label3;
|
||||
#endif
|
||||
int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__s390__)
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
}
|
||||
#elif defined(__ia64__)
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
while (start < stop) {
|
||||
asm volatile ("fc %0" :: "r"(start));
|
||||
start += 32;
|
||||
}
|
||||
asm volatile (";;sync.i;;srlz.i;;");
|
||||
}
|
||||
#elif defined(__powerpc__)
|
||||
|
||||
#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
|
||||
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
unsigned long p;
|
||||
|
||||
start &= ~(MIN_CACHE_LINE_SIZE - 1);
|
||||
stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
|
||||
|
||||
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
||||
asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
|
||||
}
|
||||
asm volatile ("sync" : : : "memory");
|
||||
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
|
||||
asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
|
||||
}
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("isync" : : : "memory");
|
||||
}
|
||||
#elif defined(__alpha__)
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
asm ("imb");
|
||||
}
|
||||
#elif defined(__sparc__)
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
unsigned long p;
|
||||
|
||||
p = start & ~(8UL - 1UL);
|
||||
stop = (stop + (8UL - 1UL)) & ~(8UL - 1UL);
|
||||
|
||||
for (; p < stop; p += 8)
|
||||
__asm__ __volatile__("flush\t%0" : : "r" (p));
|
||||
}
|
||||
#elif defined(__arm__)
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
register unsigned long _beg __asm ("a1") = start;
|
||||
register unsigned long _end __asm ("a2") = stop;
|
||||
register unsigned long _flg __asm ("a3") = 0;
|
||||
__asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
|
||||
}
|
||||
#elif defined(__mc68000)
|
||||
|
||||
# include <asm/cachectl.h>
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16);
|
||||
}
|
||||
#elif defined(__mips__)
|
||||
|
||||
#include <sys/cachectl.h>
|
||||
static inline void flush_icache_range(unsigned long start, unsigned long stop)
|
||||
{
|
||||
_flush_cache ((void *)start, stop - start, BCACHE);
|
||||
}
|
||||
#else
|
||||
#error unsupported CPU
|
||||
#endif
|
||||
|
||||
#ifdef __alpha__
|
||||
|
||||
register int gp asm("$29");
|
||||
|
||||
static inline void immediate_ldah(void *p, int val) {
|
||||
uint32_t *dest = p;
|
||||
long high = ((val >> 16) + ((val >> 15) & 1)) & 0xffff;
|
||||
|
||||
*dest &= ~0xffff;
|
||||
*dest |= high;
|
||||
*dest |= 31 << 16;
|
||||
}
|
||||
static inline void immediate_lda(void *dest, int val) {
|
||||
*(uint16_t *) dest = val;
|
||||
}
|
||||
void fix_bsr(void *p, int offset) {
|
||||
uint32_t *dest = p;
|
||||
*dest &= ~((1 << 21) - 1);
|
||||
*dest |= (offset >> 2) & ((1 << 21) - 1);
|
||||
}
|
||||
|
||||
#endif /* __alpha__ */
|
||||
|
||||
#ifdef __arm__
|
||||
|
||||
#define ARM_LDR_TABLE_SIZE 1024
|
||||
|
||||
typedef struct LDREntry {
|
||||
uint8_t *ptr;
|
||||
uint32_t *data_ptr;
|
||||
unsigned type:2;
|
||||
} LDREntry;
|
||||
|
||||
static LDREntry arm_ldr_table[1024];
|
||||
static uint32_t arm_data_table[ARM_LDR_TABLE_SIZE];
|
||||
|
||||
extern char exec_loop;
|
||||
|
||||
static inline void arm_reloc_pc24(uint32_t *ptr, uint32_t insn, int val)
|
||||
{
|
||||
*ptr = (insn & ~0xffffff) | ((insn + ((val - (int)ptr) >> 2)) & 0xffffff);
|
||||
}
|
||||
|
||||
static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
|
||||
LDREntry *ldr_start, LDREntry *ldr_end,
|
||||
uint32_t *data_start, uint32_t *data_end,
|
||||
int gen_jmp)
|
||||
{
|
||||
LDREntry *le;
|
||||
uint32_t *ptr;
|
||||
int offset, data_size, target;
|
||||
uint8_t *data_ptr;
|
||||
uint32_t insn;
|
||||
uint32_t mask;
|
||||
|
||||
data_size = (data_end - data_start) << 2;
|
||||
|
||||
if (gen_jmp) {
|
||||
/* generate branch to skip the data */
|
||||
if (data_size == 0)
|
||||
return gen_code_ptr;
|
||||
target = (long)gen_code_ptr + data_size + 4;
|
||||
arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target);
|
||||
gen_code_ptr += 4;
|
||||
}
|
||||
|
||||
/* copy the data */
|
||||
data_ptr = gen_code_ptr;
|
||||
memcpy(gen_code_ptr, data_start, data_size);
|
||||
gen_code_ptr += data_size;
|
||||
|
||||
/* patch the ldr to point to the data */
|
||||
for(le = ldr_start; le < ldr_end; le++) {
|
||||
ptr = (uint32_t *)le->ptr;
|
||||
offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
|
||||
(unsigned long)data_ptr -
|
||||
(unsigned long)ptr - 8;
|
||||
if (offset < 0) {
|
||||
fprintf(stderr, "Negative constant pool offset\n");
|
||||
abort();
|
||||
}
|
||||
switch (le->type) {
|
||||
case 0: /* ldr */
|
||||
mask = ~0x00800fff;
|
||||
if (offset >= 4096) {
|
||||
fprintf(stderr, "Bad ldr offset\n");
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
case 1: /* ldc */
|
||||
mask = ~0x008000ff;
|
||||
if (offset >= 1024 ) {
|
||||
fprintf(stderr, "Bad ldc offset\n");
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
case 2: /* add */
|
||||
mask = ~0xfff;
|
||||
if (offset >= 1024 ) {
|
||||
fprintf(stderr, "Bad add offset\n");
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Bad pc relative fixup\n");
|
||||
abort();
|
||||
}
|
||||
insn = *ptr & mask;
|
||||
switch (le->type) {
|
||||
case 0: /* ldr */
|
||||
insn |= offset | 0x00800000;
|
||||
break;
|
||||
case 1: /* ldc */
|
||||
insn |= (offset >> 2) | 0x00800000;
|
||||
break;
|
||||
case 2: /* add */
|
||||
insn |= (offset >> 2) | 0xf00;
|
||||
break;
|
||||
}
|
||||
*ptr = insn;
|
||||
}
|
||||
return gen_code_ptr;
|
||||
}
|
||||
|
||||
#endif /* __arm__ */
|
||||
|
||||
#ifdef __ia64
|
||||
|
||||
/* Patch instruction with "val" where "mask" has 1 bits. */
|
||||
static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val)
|
||||
{
|
||||
uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) (insn_addr & -16);
|
||||
# define insn_mask ((1UL << 41) - 1)
|
||||
unsigned long shift;
|
||||
|
||||
b0 = b[0]; b1 = b[1];
|
||||
shift = 5 + 41 * (insn_addr % 16); /* 5 template, 3 x 41-bit insns */
|
||||
if (shift >= 64) {
|
||||
m1 = mask << (shift - 64);
|
||||
v1 = val << (shift - 64);
|
||||
} else {
|
||||
m0 = mask << shift; m1 = mask >> (64 - shift);
|
||||
v0 = val << shift; v1 = val >> (64 - shift);
|
||||
b[0] = (b0 & ~m0) | (v0 & m0);
|
||||
}
|
||||
b[1] = (b1 & ~m1) | (v1 & m1);
|
||||
}
|
||||
|
||||
static inline void ia64_patch_imm60 (uint64_t insn_addr, uint64_t val)
|
||||
{
|
||||
ia64_patch(insn_addr,
|
||||
0x011ffffe000UL,
|
||||
( ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */
|
||||
| ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */));
|
||||
ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18);
|
||||
}
|
||||
|
||||
static inline void ia64_imm64 (void *insn, uint64_t val)
|
||||
{
|
||||
/* Ignore the slot number of the relocation; GCC and Intel
|
||||
toolchains differed for some time on whether IMM64 relocs are
|
||||
against slot 1 (Intel) or slot 2 (GCC). */
|
||||
uint64_t insn_addr = (uint64_t) insn & ~3UL;
|
||||
|
||||
ia64_patch(insn_addr + 2,
|
||||
0x01fffefe000UL,
|
||||
( ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */
|
||||
| ((val & 0x0000000000200000UL) << 0) /* bit 21 -> 21 */
|
||||
| ((val & 0x00000000001f0000UL) << 6) /* bit 16 -> 22 */
|
||||
| ((val & 0x000000000000ff80UL) << 20) /* bit 7 -> 27 */
|
||||
| ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */)
|
||||
);
|
||||
ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22);
|
||||
}
|
||||
|
||||
static inline void ia64_imm60b (void *insn, uint64_t val)
|
||||
{
|
||||
/* Ignore the slot number of the relocation; GCC and Intel
|
||||
toolchains differed for some time on whether IMM64 relocs are
|
||||
against slot 1 (Intel) or slot 2 (GCC). */
|
||||
uint64_t insn_addr = (uint64_t) insn & ~3UL;
|
||||
|
||||
if (val + ((uint64_t) 1 << 59) >= (1UL << 60))
|
||||
fprintf(stderr, "%s: value %ld out of IMM60 range\n",
|
||||
__FUNCTION__, (int64_t) val);
|
||||
ia64_patch_imm60(insn_addr + 2, val);
|
||||
}
|
||||
|
||||
static inline void ia64_imm22 (void *insn, uint64_t val)
|
||||
{
|
||||
if (val + (1 << 21) >= (1 << 22))
|
||||
fprintf(stderr, "%s: value %li out of IMM22 range\n",
|
||||
__FUNCTION__, (int64_t)val);
|
||||
ia64_patch((uint64_t) insn, 0x01fffcfe000UL,
|
||||
( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
|
||||
| ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */
|
||||
| ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */
|
||||
| ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */));
|
||||
}
|
||||
|
||||
/* Like ia64_imm22(), but also clear bits 20-21. For addl, this has
|
||||
the effect of turning "addl rX=imm22,rY" into "addl
|
||||
rX=imm22,r0". */
|
||||
static inline void ia64_imm22_r0 (void *insn, uint64_t val)
|
||||
{
|
||||
if (val + (1 << 21) >= (1 << 22))
|
||||
fprintf(stderr, "%s: value %li out of IMM22 range\n",
|
||||
__FUNCTION__, (int64_t)val);
|
||||
ia64_patch((uint64_t) insn, 0x01fffcfe000UL | (0x3UL << 20),
|
||||
( ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
|
||||
| ((val & 0x1f0000UL) << 6) /* bit 16 -> 22 */
|
||||
| ((val & 0x00ff80UL) << 20) /* bit 7 -> 27 */
|
||||
| ((val & 0x00007fUL) << 13) /* bit 0 -> 13 */));
|
||||
}
|
||||
|
||||
static inline void ia64_imm21b (void *insn, uint64_t val)
|
||||
{
|
||||
if (val + (1 << 20) >= (1 << 21))
|
||||
fprintf(stderr, "%s: value %li out of IMM21b range\n",
|
||||
__FUNCTION__, (int64_t)val);
|
||||
ia64_patch((uint64_t) insn, 0x11ffffe000UL,
|
||||
( ((val & 0x100000UL) << 16) /* bit 20 -> 36 */
|
||||
| ((val & 0x0fffffUL) << 13) /* bit 0 -> 13 */));
|
||||
}
|
||||
|
||||
static inline void ia64_nop_b (void *insn)
|
||||
{
|
||||
ia64_patch((uint64_t) insn, (1UL << 41) - 1, 2UL << 37);
|
||||
}
|
||||
|
||||
static inline void ia64_ldxmov(void *insn, uint64_t val)
|
||||
{
|
||||
if (val + (1 << 21) < (1 << 22))
|
||||
ia64_patch((uint64_t) insn, 0x1fff80fe000UL, 8UL << 37);
|
||||
}
|
||||
|
||||
static inline int ia64_patch_ltoff(void *insn, uint64_t val,
|
||||
int relaxable)
|
||||
{
|
||||
if (relaxable && (val + (1 << 21) < (1 << 22))) {
|
||||
ia64_imm22_r0(insn, val);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ia64_fixup {
|
||||
struct ia64_fixup *next;
|
||||
void *addr; /* address that needs to be patched */
|
||||
long value;
|
||||
};
|
||||
|
||||
#define IA64_PLT(insn, plt_index) \
|
||||
do { \
|
||||
struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \
|
||||
fixup->next = plt_fixes; \
|
||||
plt_fixes = fixup; \
|
||||
fixup->addr = (insn); \
|
||||
fixup->value = (plt_index); \
|
||||
plt_offset[(plt_index)] = 1; \
|
||||
} while (0)
|
||||
|
||||
#define IA64_LTOFF(insn, val, relaxable) \
|
||||
do { \
|
||||
if (ia64_patch_ltoff(insn, val, relaxable)) { \
|
||||
struct ia64_fixup *fixup = alloca(sizeof(*fixup)); \
|
||||
fixup->next = ltoff_fixes; \
|
||||
ltoff_fixes = fixup; \
|
||||
fixup->addr = (insn); \
|
||||
fixup->value = (val); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline void ia64_apply_fixes (uint8_t **gen_code_pp,
|
||||
struct ia64_fixup *ltoff_fixes,
|
||||
uint64_t gp,
|
||||
struct ia64_fixup *plt_fixes,
|
||||
int num_plts,
|
||||
unsigned long *plt_target,
|
||||
unsigned int *plt_offset)
|
||||
{
|
||||
static const uint8_t plt_bundle[] = {
|
||||
0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; movl r1=GP */
|
||||
0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60,
|
||||
|
||||
0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; brl IP */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0
|
||||
};
|
||||
uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start;
|
||||
uint64_t *vp;
|
||||
struct ia64_fixup *fixup;
|
||||
unsigned int offset = 0;
|
||||
struct fdesc {
|
||||
long ip;
|
||||
long gp;
|
||||
} *fdesc;
|
||||
int i;
|
||||
|
||||
if (plt_fixes) {
|
||||
plt_start = gen_code_ptr;
|
||||
|
||||
for (i = 0; i < num_plts; ++i) {
|
||||
if (plt_offset[i]) {
|
||||
plt_offset[i] = offset;
|
||||
offset += sizeof(plt_bundle);
|
||||
|
||||
fdesc = (struct fdesc *) plt_target[i];
|
||||
memcpy(gen_code_ptr, plt_bundle, sizeof(plt_bundle));
|
||||
ia64_imm64 (gen_code_ptr + 0x02, fdesc->gp);
|
||||
ia64_imm60b(gen_code_ptr + 0x12,
|
||||
(fdesc->ip - (long) (gen_code_ptr + 0x10)) >> 4);
|
||||
gen_code_ptr += sizeof(plt_bundle);
|
||||
}
|
||||
}
|
||||
|
||||
for (fixup = plt_fixes; fixup; fixup = fixup->next)
|
||||
ia64_imm21b(fixup->addr,
|
||||
((long) plt_start + plt_offset[fixup->value]
|
||||
- ((long) fixup->addr & ~0xf)) >> 4);
|
||||
}
|
||||
|
||||
got_start = gen_code_ptr;
|
||||
|
||||
/* First, create the GOT: */
|
||||
for (fixup = ltoff_fixes; fixup; fixup = fixup->next) {
|
||||
/* first check if we already have this value in the GOT: */
|
||||
for (vp = (uint64_t *) got_start; vp < (uint64_t *) gen_code_ptr; ++vp)
|
||||
if (*vp == fixup->value)
|
||||
break;
|
||||
if (vp == (uint64_t *) gen_code_ptr) {
|
||||
/* Nope, we need to put the value in the GOT: */
|
||||
*vp = fixup->value;
|
||||
gen_code_ptr += 8;
|
||||
}
|
||||
ia64_imm22(fixup->addr, (long) vp - gp);
|
||||
}
|
||||
/* Keep code ptr aligned. */
|
||||
if ((long) gen_code_ptr & 15)
|
||||
gen_code_ptr += 8;
|
||||
*gen_code_pp = gen_code_ptr;
|
||||
}
|
||||
|
||||
#endif
|
55
exec-all.h
55
exec-all.h
@ -36,10 +36,6 @@ struct TranslationBlock;
|
||||
|
||||
#define OPPARAM_BUF_SIZE (OPC_BUF_SIZE * 3)
|
||||
|
||||
extern uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
||||
extern uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
extern long gen_labels[OPC_BUF_SIZE];
|
||||
extern int nb_gen_labels;
|
||||
extern target_ulong gen_opc_pc[OPC_BUF_SIZE];
|
||||
extern target_ulong gen_opc_npc[OPC_BUF_SIZE];
|
||||
extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
|
||||
@ -63,8 +59,8 @@ extern int loglevel;
|
||||
|
||||
int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
|
||||
int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
|
||||
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
|
||||
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);
|
||||
int cpu_restore_state(struct TranslationBlock *tb,
|
||||
@ -120,6 +116,7 @@ static inline int tlb_set_page(CPUState *env, target_ulong vaddr,
|
||||
#elif defined(__powerpc__)
|
||||
#define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024)
|
||||
#else
|
||||
/* XXX: make it dynamic on x86 */
|
||||
#define CODE_GEN_BUFFER_SIZE (16 * 1024 * 1024)
|
||||
#endif
|
||||
|
||||
@ -136,7 +133,7 @@ static inline int tlb_set_page(CPUState *env, target_ulong vaddr,
|
||||
|
||||
#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE)
|
||||
|
||||
#if defined(__powerpc__)
|
||||
#if defined(__powerpc__) || defined(__x86_64__)
|
||||
#define USE_DIRECT_JUMP
|
||||
#endif
|
||||
#if defined(__i386__) && !defined(_WIN32)
|
||||
@ -169,7 +166,7 @@ typedef struct TranslationBlock {
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
uint16_t tb_jmp_offset[4]; /* offset of jump instruction */
|
||||
#else
|
||||
uint32_t tb_next[2]; /* address of jump generated code */
|
||||
unsigned long tb_next[2]; /* address of jump generated code */
|
||||
#endif
|
||||
/* list of TBs jumping to this one. This is a circular list using
|
||||
the two least significant bits of the pointers to tell what is
|
||||
@ -228,7 +225,7 @@ static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr
|
||||
asm volatile ("sync" : : : "memory");
|
||||
asm volatile ("isync" : : : "memory");
|
||||
}
|
||||
#elif defined(__i386__)
|
||||
#elif defined(__i386__) || defined(__x86_64__)
|
||||
static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr)
|
||||
{
|
||||
/* patch the branch destination */
|
||||
@ -294,48 +291,6 @@ TranslationBlock *tb_find_pc(unsigned long pc_ptr);
|
||||
#define ASM_OP_LABEL_NAME(n, opname) \
|
||||
ASM_NAME(__op_label) #n "." ASM_NAME(opname)
|
||||
|
||||
#if defined(__powerpc__)
|
||||
|
||||
/* we patch the jump instruction directly */
|
||||
#define GOTO_TB(opname, tbparam, n)\
|
||||
do {\
|
||||
asm volatile (ASM_DATA_SECTION\
|
||||
ASM_OP_LABEL_NAME(n, opname) ":\n"\
|
||||
".long 1f\n"\
|
||||
ASM_PREVIOUS_SECTION \
|
||||
"b " ASM_NAME(__op_jmp) #n "\n"\
|
||||
"1:\n");\
|
||||
} while (0)
|
||||
|
||||
#elif defined(__i386__) && defined(USE_DIRECT_JUMP)
|
||||
|
||||
/* we patch the jump instruction directly */
|
||||
#define GOTO_TB(opname, tbparam, n)\
|
||||
do {\
|
||||
asm volatile (".section .data\n"\
|
||||
ASM_OP_LABEL_NAME(n, opname) ":\n"\
|
||||
".long 1f\n"\
|
||||
ASM_PREVIOUS_SECTION \
|
||||
"jmp " ASM_NAME(__op_jmp) #n "\n"\
|
||||
"1:\n");\
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
/* jump to next block operations (more portable code, does not need
|
||||
cache flushing, but slower because of indirect jump) */
|
||||
#define GOTO_TB(opname, tbparam, n)\
|
||||
do {\
|
||||
static void __attribute__((used)) *dummy ## n = &&dummy_label ## n;\
|
||||
static void __attribute__((used)) *__op_label ## n \
|
||||
__asm__(ASM_OP_LABEL_NAME(n, opname)) = &&label ## n;\
|
||||
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
|
||||
label ## n: ;\
|
||||
dummy_label ## n: ;\
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
|
||||
extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
|
||||
extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
|
||||
|
46
exec.c
46
exec.c
@ -312,6 +312,7 @@ void cpu_exec_init(CPUState *env)
|
||||
int cpu_index;
|
||||
|
||||
if (!code_gen_ptr) {
|
||||
cpu_gen_init();
|
||||
code_gen_ptr = code_gen_buffer;
|
||||
page_init();
|
||||
io_mem_init();
|
||||
@ -1238,10 +1239,10 @@ CPULogItem cpu_log_items[] = {
|
||||
{ CPU_LOG_TB_IN_ASM, "in_asm",
|
||||
"show target assembly code for each compiled TB" },
|
||||
{ CPU_LOG_TB_OP, "op",
|
||||
"show micro ops for each compiled TB (only usable if 'in_asm' used)" },
|
||||
"show micro ops for each compiled TB" },
|
||||
#ifdef TARGET_I386
|
||||
{ CPU_LOG_TB_OP_OPT, "op_opt",
|
||||
"show micro ops after optimization for each compiled TB" },
|
||||
"show micro ops before eflags optimization" },
|
||||
#endif
|
||||
{ CPU_LOG_INT, "int",
|
||||
"show interrupts/exceptions in short format" },
|
||||
@ -2935,6 +2936,7 @@ void dump_exec_info(FILE *f,
|
||||
}
|
||||
}
|
||||
/* XXX: avoid using doubles ? */
|
||||
cpu_fprintf(f, "Translation buffer state:\n");
|
||||
cpu_fprintf(f, "TB count %d\n", nb_tbs);
|
||||
cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
|
||||
nb_tbs ? target_code_size / nb_tbs : 0,
|
||||
@ -2950,9 +2952,49 @@ void dump_exec_info(FILE *f,
|
||||
nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
|
||||
direct_jmp2_count,
|
||||
nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
|
||||
cpu_fprintf(f, "\nStatistics:\n");
|
||||
cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
|
||||
cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
|
||||
cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
|
||||
#ifdef CONFIG_PROFILER
|
||||
{
|
||||
int64_t tot;
|
||||
tot = dyngen_interm_time + dyngen_code_time;
|
||||
cpu_fprintf(f, "JIT cycles %" PRId64 " (%0.3f s at 2.4 GHz)\n",
|
||||
tot, tot / 2.4e9);
|
||||
cpu_fprintf(f, "translated TBs %" PRId64 " (aborted=%" PRId64 " %0.1f%%)\n",
|
||||
dyngen_tb_count,
|
||||
dyngen_tb_count1 - dyngen_tb_count,
|
||||
dyngen_tb_count1 ? (double)(dyngen_tb_count1 - dyngen_tb_count) / dyngen_tb_count1 * 100.0 : 0);
|
||||
cpu_fprintf(f, "avg ops/TB %0.1f max=%d\n",
|
||||
dyngen_tb_count ? (double)dyngen_op_count / dyngen_tb_count : 0, dyngen_op_count_max);
|
||||
cpu_fprintf(f, "old ops/total ops %0.1f%%\n",
|
||||
dyngen_op_count ? (double)dyngen_old_op_count / dyngen_op_count * 100.0 : 0);
|
||||
cpu_fprintf(f, "deleted ops/TB %0.2f\n",
|
||||
dyngen_tb_count ?
|
||||
(double)dyngen_tcg_del_op_count / dyngen_tb_count : 0);
|
||||
cpu_fprintf(f, "cycles/op %0.1f\n",
|
||||
dyngen_op_count ? (double)tot / dyngen_op_count : 0);
|
||||
cpu_fprintf(f, "cycles/in byte %0.1f\n",
|
||||
dyngen_code_in_len ? (double)tot / dyngen_code_in_len : 0);
|
||||
cpu_fprintf(f, "cycles/out byte %0.1f\n",
|
||||
dyngen_code_out_len ? (double)tot / dyngen_code_out_len : 0);
|
||||
if (tot == 0)
|
||||
tot = 1;
|
||||
cpu_fprintf(f, " gen_interm time %0.1f%%\n",
|
||||
(double)dyngen_interm_time / tot * 100.0);
|
||||
cpu_fprintf(f, " gen_code time %0.1f%%\n",
|
||||
(double)dyngen_code_time / tot * 100.0);
|
||||
cpu_fprintf(f, "cpu_restore count %" PRId64 "\n",
|
||||
dyngen_restore_count);
|
||||
cpu_fprintf(f, " avg cycles %0.1f\n",
|
||||
dyngen_restore_count ? (double)dyngen_restore_time / dyngen_restore_count : 0);
|
||||
{
|
||||
extern void dump_op_count(void);
|
||||
dump_op_count();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
@ -216,11 +216,6 @@ void OPPROTO op_clear_irf (void)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_exit_tb (void)
|
||||
{
|
||||
EXIT_TB();
|
||||
}
|
||||
|
||||
/* Arithmetic */
|
||||
void OPPROTO op_addq (void)
|
||||
{
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
#include "tcg-op.h"
|
||||
|
||||
#define DO_SINGLE_STEP
|
||||
#define GENERATE_NOP
|
||||
@ -41,24 +42,6 @@ struct DisasContext {
|
||||
uint32_t amask;
|
||||
};
|
||||
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
#define TBPARAM(x)
|
||||
#else
|
||||
#define TBPARAM(x) (long)(x)
|
||||
#endif
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
static uint16_t *gen_opc_ptr;
|
||||
static uint32_t *gen_opparam_ptr;
|
||||
|
||||
#include "gen-op.h"
|
||||
|
||||
static always_inline void gen_op_nop (void)
|
||||
{
|
||||
#if defined(GENERATE_NOP)
|
||||
@ -1988,10 +1971,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
|
||||
int ret;
|
||||
|
||||
pc_start = tb->pc;
|
||||
gen_opc_ptr = gen_opc_buf;
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
nb_gen_labels = 0;
|
||||
ctx.pc = pc_start;
|
||||
ctx.amask = env->amask;
|
||||
#if defined (CONFIG_USER_ONLY)
|
||||
@ -2051,12 +2031,11 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
|
||||
if (ret != 1 && ret != 3) {
|
||||
gen_update_pc(&ctx);
|
||||
}
|
||||
gen_op_reset_T0();
|
||||
#if defined (DO_TB_FLUSH)
|
||||
gen_op_tb_flush();
|
||||
#endif
|
||||
/* Generate the return instruction */
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
*gen_opc_ptr = INDEX_op_end;
|
||||
if (search_pc) {
|
||||
j = gen_opc_ptr - gen_opc_buf;
|
||||
@ -2075,11 +2054,6 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
|
||||
target_disas(logfile, pc_start, ctx.pc - pc_start, 1);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
if (loglevel & CPU_LOG_TB_OP) {
|
||||
fprintf(logfile, "OP:\n");
|
||||
dump_ops(gen_opc_buf, gen_opparam_buf);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
@ -364,21 +364,6 @@ void OPPROTO op_testn_T0(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_goto_tb0(void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb0, PARAM1, 0);
|
||||
}
|
||||
|
||||
void OPPROTO op_goto_tb1(void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb1, PARAM1, 1);
|
||||
}
|
||||
|
||||
void OPPROTO op_exit_tb(void)
|
||||
{
|
||||
EXIT_TB();
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_cpsr(void)
|
||||
{
|
||||
/* Execution state bits always read as zero. */
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
#include "tcg-op.h"
|
||||
|
||||
#define ENABLE_ARCH_5J 0
|
||||
#define ENABLE_ARCH_6 arm_feature(env, ARM_FEATURE_V6)
|
||||
@ -68,27 +69,10 @@ typedef struct DisasContext {
|
||||
#define DISAS_WFI 4
|
||||
#define DISAS_SWI 5
|
||||
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
#define TBPARAM(x)
|
||||
#else
|
||||
#define TBPARAM(x) (long)(x)
|
||||
#endif
|
||||
|
||||
/* XXX: move that elsewhere */
|
||||
static uint16_t *gen_opc_ptr;
|
||||
static uint32_t *gen_opparam_ptr;
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#include "gen-op.h"
|
||||
|
||||
#define PAS_OP(pfx) { \
|
||||
gen_op_ ## pfx ## add16_T0_T1, \
|
||||
gen_op_ ## pfx ## addsubx_T0_T1, \
|
||||
@ -2432,19 +2416,14 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint32_t dest)
|
||||
|
||||
tb = s->tb;
|
||||
if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
|
||||
if (n == 0)
|
||||
gen_op_goto_tb0(TBPARAM(tb));
|
||||
else
|
||||
gen_op_goto_tb1(TBPARAM(tb));
|
||||
tcg_gen_goto_tb(n);
|
||||
gen_op_movl_T0_im(dest);
|
||||
gen_op_movl_r15_T0();
|
||||
gen_op_movl_T0_im((long)tb + n);
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb((long)tb + n);
|
||||
} else {
|
||||
gen_op_movl_T0_im(dest);
|
||||
gen_op_movl_r15_T0();
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7486,9 +7465,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
||||
|
||||
dc->tb = tb;
|
||||
|
||||
gen_opc_ptr = gen_opc_buf;
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
|
||||
dc->is_jmp = DISAS_NEXT;
|
||||
dc->pc = pc_start;
|
||||
@ -7506,7 +7483,6 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
||||
}
|
||||
#endif
|
||||
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
|
||||
nb_gen_labels = 0;
|
||||
lj = -1;
|
||||
/* Reset the conditional execution bits immediately. This avoids
|
||||
complications trying to do it at the end of the block. */
|
||||
@ -7625,8 +7601,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
|
||||
case DISAS_JUMP:
|
||||
case DISAS_UPDATE:
|
||||
/* indicate that the hash table must be used to find the next TB */
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
break;
|
||||
case DISAS_TB_JUMP:
|
||||
/* nothing more to generate */
|
||||
@ -7654,11 +7629,6 @@ done_generating:
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
|
||||
target_disas(logfile, pc_start, dc->pc - pc_start, env->thumb);
|
||||
fprintf(logfile, "\n");
|
||||
if (loglevel & (CPU_LOG_TB_OP)) {
|
||||
fprintf(logfile, "OP:\n");
|
||||
dump_ops(gen_opc_buf, gen_opparam_buf);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (search_pc) {
|
||||
|
@ -151,23 +151,6 @@
|
||||
|
||||
/* Microcode. */
|
||||
|
||||
void OPPROTO op_exit_tb (void)
|
||||
{
|
||||
EXIT_TB();
|
||||
}
|
||||
|
||||
void OPPROTO op_goto_tb0 (void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb0, PARAM1, 0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_goto_tb1 (void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb1, PARAM1, 1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_break_im(void)
|
||||
{
|
||||
env->trapnr = PARAM1;
|
||||
@ -1268,7 +1251,7 @@ void OPPROTO op_movl_btarget_T0 (void)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_jmp (void)
|
||||
void OPPROTO op_jmp1 (void)
|
||||
{
|
||||
env->pc = env->btarget;
|
||||
RETURN();
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
#include "tcg-op.h"
|
||||
#include "crisv32-decode.h"
|
||||
|
||||
#define CRIS_STATS 0
|
||||
@ -67,12 +68,6 @@
|
||||
#define DIS(x)
|
||||
#endif
|
||||
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
#define TBPARAM(x)
|
||||
#else
|
||||
#define TBPARAM(x) (long)(x)
|
||||
#endif
|
||||
|
||||
#define BUG() (gen_BUG(dc, __FILE__, __LINE__))
|
||||
#define BUG_ON(x) ({if (x) BUG();})
|
||||
|
||||
@ -85,17 +80,6 @@
|
||||
#define CC_MASK_NZVC 0xf
|
||||
#define CC_MASK_RNZV 0x10e
|
||||
|
||||
static uint16_t *gen_opc_ptr;
|
||||
static uint32_t *gen_opparam_ptr;
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
#include "gen-op.h"
|
||||
|
||||
/* This is the state at translation time. */
|
||||
typedef struct DisasContext {
|
||||
CPUState *env;
|
||||
@ -264,15 +248,14 @@ static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest)
|
||||
TranslationBlock *tb;
|
||||
tb = dc->tb;
|
||||
if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
|
||||
if (n == 0)
|
||||
gen_op_goto_tb0(TBPARAM(tb));
|
||||
else
|
||||
gen_op_goto_tb1(TBPARAM(tb));
|
||||
gen_op_movl_T0_0();
|
||||
#if 0
|
||||
/* XXX: this code is not finished */
|
||||
tcg_gen_goto_tb(n);
|
||||
#endif
|
||||
tcg_gen_exit_tb(0);
|
||||
} else {
|
||||
gen_op_movl_T0_0();
|
||||
tcg_gen_exit_tb(0);
|
||||
}
|
||||
gen_op_exit_tb();
|
||||
}
|
||||
|
||||
/* Sign extend at translation time. */
|
||||
@ -2325,9 +2308,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
||||
dc->env = env;
|
||||
dc->tb = tb;
|
||||
|
||||
gen_opc_ptr = gen_opc_buf;
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
|
||||
dc->is_jmp = DISAS_NEXT;
|
||||
dc->pc = pc_start;
|
||||
@ -2374,7 +2355,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
||||
if (dc->delayed_branch == 0)
|
||||
{
|
||||
if (dc->bcc == CC_A) {
|
||||
gen_op_jmp ();
|
||||
gen_op_jmp1 ();
|
||||
dc->is_jmp = DISAS_UPDATE;
|
||||
}
|
||||
else {
|
||||
@ -2409,9 +2390,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
||||
case DISAS_UPDATE:
|
||||
/* indicate that the hash table must be used
|
||||
to find the next TB */
|
||||
/* T0 is used to index the jmp tables. */
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
break;
|
||||
case DISAS_TB_JUMP:
|
||||
/* nothing more to generate */
|
||||
@ -2434,11 +2413,6 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
|
||||
target_disas(logfile, pc_start, dc->pc + 4 - pc_start, 0);
|
||||
fprintf(logfile, "\n");
|
||||
if (loglevel & CPU_LOG_TB_OP) {
|
||||
fprintf(logfile, "OP:\n");
|
||||
dump_ops(gen_opc_buf, gen_opparam_buf);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
@ -181,8 +181,9 @@ void __hidden cpu_loop_exit(void);
|
||||
|
||||
void OPPROTO op_movl_eflags_T0(void);
|
||||
void OPPROTO op_movl_T0_eflags(void);
|
||||
void helper_divl_EAX_T0(void);
|
||||
void helper_idivl_EAX_T0(void);
|
||||
|
||||
#include "helper.h"
|
||||
|
||||
void helper_mulq_EAX_T0(void);
|
||||
void helper_imulq_EAX_T0(void);
|
||||
void helper_imulq_T0_T1(void);
|
||||
|
@ -1608,13 +1608,13 @@ int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den)
|
||||
}
|
||||
#endif
|
||||
|
||||
void helper_divl_EAX_T0(void)
|
||||
void helper_divl_EAX_T0(target_ulong t0)
|
||||
{
|
||||
unsigned int den, r;
|
||||
uint64_t num, q;
|
||||
|
||||
num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
|
||||
den = T0;
|
||||
den = t0;
|
||||
if (den == 0) {
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
}
|
||||
@ -1630,13 +1630,13 @@ void helper_divl_EAX_T0(void)
|
||||
EDX = (uint32_t)r;
|
||||
}
|
||||
|
||||
void helper_idivl_EAX_T0(void)
|
||||
void helper_idivl_EAX_T0(target_ulong t0)
|
||||
{
|
||||
int den, r;
|
||||
int64_t num, q;
|
||||
|
||||
num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
|
||||
den = T0;
|
||||
den = t0;
|
||||
if (den == 0) {
|
||||
raise_exception(EXCP00_DIVZ);
|
||||
}
|
||||
|
4
target-i386/helper.h
Normal file
4
target-i386/helper.h
Normal file
@ -0,0 +1,4 @@
|
||||
#define TCG_HELPER_PROTO
|
||||
|
||||
void TCG_HELPER_PROTO helper_divl_EAX_T0(target_ulong t0);
|
||||
void TCG_HELPER_PROTO helper_idivl_EAX_T0(target_ulong t0);
|
270
target-i386/op.c
270
target-i386/op.c
@ -172,31 +172,6 @@ void OPPROTO op_testl_T0_T1_cc(void)
|
||||
|
||||
/* operations without flags */
|
||||
|
||||
void OPPROTO op_addl_T0_T1(void)
|
||||
{
|
||||
T0 += T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_orl_T0_T1(void)
|
||||
{
|
||||
T0 |= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_andl_T0_T1(void)
|
||||
{
|
||||
T0 &= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_subl_T0_T1(void)
|
||||
{
|
||||
T0 -= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_xorl_T0_T1(void)
|
||||
{
|
||||
T0 ^= T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_negl_T0(void)
|
||||
{
|
||||
T0 = -T0;
|
||||
@ -217,18 +192,6 @@ void OPPROTO op_notl_T0(void)
|
||||
T0 = ~T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_bswapl_T0(void)
|
||||
{
|
||||
T0 = bswap32(T0);
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
void OPPROTO op_bswapq_T0(void)
|
||||
{
|
||||
helper_bswapq_T0();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* multiply/divide */
|
||||
|
||||
/* XXX: add eflags optimizations */
|
||||
@ -399,16 +362,6 @@ void OPPROTO op_idivw_AX_T0(void)
|
||||
EDX = (EDX & ~0xffff) | r;
|
||||
}
|
||||
|
||||
void OPPROTO op_divl_EAX_T0(void)
|
||||
{
|
||||
helper_divl_EAX_T0();
|
||||
}
|
||||
|
||||
void OPPROTO op_idivl_EAX_T0(void)
|
||||
{
|
||||
helper_idivl_EAX_T0();
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
void OPPROTO op_divq_EAX_T0(void)
|
||||
{
|
||||
@ -424,46 +377,6 @@ void OPPROTO op_idivq_EAX_T0(void)
|
||||
/* constant load & misc op */
|
||||
|
||||
/* XXX: consistent names */
|
||||
void OPPROTO op_movl_T0_imu(void)
|
||||
{
|
||||
T0 = (uint32_t)PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_im(void)
|
||||
{
|
||||
T0 = (int32_t)PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_T0_im(void)
|
||||
{
|
||||
T0 += PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_andl_T0_ffff(void)
|
||||
{
|
||||
T0 = T0 & 0xffff;
|
||||
}
|
||||
|
||||
void OPPROTO op_andl_T0_im(void)
|
||||
{
|
||||
T0 = T0 & PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_T1(void)
|
||||
{
|
||||
T0 = T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T1_imu(void)
|
||||
{
|
||||
T1 = (uint32_t)PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T1_im(void)
|
||||
{
|
||||
T1 = (int32_t)PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_T1_im(void)
|
||||
{
|
||||
T1 += PARAM1;
|
||||
@ -474,26 +387,6 @@ void OPPROTO op_movl_T1_A0(void)
|
||||
T1 = A0;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_A0_im(void)
|
||||
{
|
||||
A0 = (uint32_t)PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_A0_im(void)
|
||||
{
|
||||
A0 = (uint32_t)(A0 + PARAM1);
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_A0_seg(void)
|
||||
{
|
||||
A0 = (uint32_t)*(target_ulong *)((char *)env + PARAM1);
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_A0_seg(void)
|
||||
{
|
||||
A0 = (uint32_t)(A0 + *(target_ulong *)((char *)env + PARAM1));
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_A0_AL(void)
|
||||
{
|
||||
A0 = (uint32_t)(A0 + (EAX & 0xff));
|
||||
@ -523,46 +416,6 @@ typedef union UREG64 {
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
|
||||
void OPPROTO op_movq_T0_im64(void)
|
||||
{
|
||||
T0 = PARAMQ1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movq_T1_im64(void)
|
||||
{
|
||||
T1 = PARAMQ1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movq_A0_im(void)
|
||||
{
|
||||
A0 = (int32_t)PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movq_A0_im64(void)
|
||||
{
|
||||
A0 = PARAMQ1;
|
||||
}
|
||||
|
||||
void OPPROTO op_addq_A0_im(void)
|
||||
{
|
||||
A0 = (A0 + (int32_t)PARAM1);
|
||||
}
|
||||
|
||||
void OPPROTO op_addq_A0_im64(void)
|
||||
{
|
||||
A0 = (A0 + PARAMQ1);
|
||||
}
|
||||
|
||||
void OPPROTO op_movq_A0_seg(void)
|
||||
{
|
||||
A0 = *(target_ulong *)((char *)env + PARAM1);
|
||||
}
|
||||
|
||||
void OPPROTO op_addq_A0_seg(void)
|
||||
{
|
||||
A0 += *(target_ulong *)((char *)env + PARAM1);
|
||||
}
|
||||
|
||||
void OPPROTO op_addq_A0_AL(void)
|
||||
{
|
||||
A0 = (A0 + (EAX & 0xff));
|
||||
@ -570,11 +423,6 @@ void OPPROTO op_addq_A0_AL(void)
|
||||
|
||||
#endif
|
||||
|
||||
void OPPROTO op_andl_A0_ffff(void)
|
||||
{
|
||||
A0 = A0 & 0xffff;
|
||||
}
|
||||
|
||||
/* memory access */
|
||||
|
||||
#define MEMSUFFIX _raw
|
||||
@ -588,30 +436,6 @@ void OPPROTO op_andl_A0_ffff(void)
|
||||
#include "ops_mem.h"
|
||||
#endif
|
||||
|
||||
/* indirect jump */
|
||||
|
||||
void OPPROTO op_jmp_T0(void)
|
||||
{
|
||||
EIP = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_eip_im(void)
|
||||
{
|
||||
EIP = (uint32_t)PARAM1;
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
void OPPROTO op_movq_eip_im(void)
|
||||
{
|
||||
EIP = (int32_t)PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_movq_eip_im64(void)
|
||||
{
|
||||
EIP = PARAMQ1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void OPPROTO op_hlt(void)
|
||||
{
|
||||
helper_hlt();
|
||||
@ -735,16 +559,6 @@ void OPPROTO op_single_step(void)
|
||||
helper_single_step();
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_T0_0(void)
|
||||
{
|
||||
T0 = 0;
|
||||
}
|
||||
|
||||
void OPPROTO op_exit_tb(void)
|
||||
{
|
||||
EXIT_TB();
|
||||
}
|
||||
|
||||
/* multiple size ops */
|
||||
|
||||
#define ldul ldl
|
||||
@ -879,75 +693,6 @@ void OPPROTO op_decq_ECX(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* push/pop utils */
|
||||
|
||||
void op_addl_A0_SS(void)
|
||||
{
|
||||
A0 = (uint32_t)(A0 + env->segs[R_SS].base);
|
||||
}
|
||||
|
||||
void op_subl_A0_2(void)
|
||||
{
|
||||
A0 = (uint32_t)(A0 - 2);
|
||||
}
|
||||
|
||||
void op_subl_A0_4(void)
|
||||
{
|
||||
A0 = (uint32_t)(A0 - 4);
|
||||
}
|
||||
|
||||
void op_addl_ESP_4(void)
|
||||
{
|
||||
ESP = (uint32_t)(ESP + 4);
|
||||
}
|
||||
|
||||
void op_addl_ESP_2(void)
|
||||
{
|
||||
ESP = (uint32_t)(ESP + 2);
|
||||
}
|
||||
|
||||
void op_addw_ESP_4(void)
|
||||
{
|
||||
ESP = (ESP & ~0xffff) | ((ESP + 4) & 0xffff);
|
||||
}
|
||||
|
||||
void op_addw_ESP_2(void)
|
||||
{
|
||||
ESP = (ESP & ~0xffff) | ((ESP + 2) & 0xffff);
|
||||
}
|
||||
|
||||
void op_addl_ESP_im(void)
|
||||
{
|
||||
ESP = (uint32_t)(ESP + PARAM1);
|
||||
}
|
||||
|
||||
void op_addw_ESP_im(void)
|
||||
{
|
||||
ESP = (ESP & ~0xffff) | ((ESP + PARAM1) & 0xffff);
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
void op_subq_A0_2(void)
|
||||
{
|
||||
A0 -= 2;
|
||||
}
|
||||
|
||||
void op_subq_A0_8(void)
|
||||
{
|
||||
A0 -= 8;
|
||||
}
|
||||
|
||||
void op_addq_ESP_8(void)
|
||||
{
|
||||
ESP += 8;
|
||||
}
|
||||
|
||||
void op_addq_ESP_im(void)
|
||||
{
|
||||
ESP += PARAM1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void OPPROTO op_rdtsc(void)
|
||||
{
|
||||
helper_rdtsc();
|
||||
@ -1362,16 +1107,6 @@ void OPPROTO op_clts(void)
|
||||
|
||||
/* flags handling */
|
||||
|
||||
void OPPROTO op_goto_tb0(void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb0, PARAM1, 0);
|
||||
}
|
||||
|
||||
void OPPROTO op_goto_tb1(void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb1, PARAM1, 1);
|
||||
}
|
||||
|
||||
void OPPROTO op_jmp_label(void)
|
||||
{
|
||||
GOTO_LABEL_PARAM(1);
|
||||
@ -1451,11 +1186,6 @@ void OPPROTO op_xor_T0_1(void)
|
||||
T0 ^= 1;
|
||||
}
|
||||
|
||||
void OPPROTO op_set_cc_op(void)
|
||||
{
|
||||
CC_OP = PARAM1;
|
||||
}
|
||||
|
||||
void OPPROTO op_mov_T0_cc(void)
|
||||
{
|
||||
T0 = cc_table[CC_OP].compute_all();
|
||||
|
@ -18,110 +18,6 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
void OPPROTO glue(op_movl_A0,REGNAME)(void)
|
||||
{
|
||||
A0 = (uint32_t)REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_addl_A0,REGNAME)(void)
|
||||
{
|
||||
A0 = (uint32_t)(A0 + REG);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_addl_A0,REGNAME),_s1)(void)
|
||||
{
|
||||
A0 = (uint32_t)(A0 + (REG << 1));
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_addl_A0,REGNAME),_s2)(void)
|
||||
{
|
||||
A0 = (uint32_t)(A0 + (REG << 2));
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_addl_A0,REGNAME),_s3)(void)
|
||||
{
|
||||
A0 = (uint32_t)(A0 + (REG << 3));
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
void OPPROTO glue(op_movq_A0,REGNAME)(void)
|
||||
{
|
||||
A0 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_addq_A0,REGNAME)(void)
|
||||
{
|
||||
A0 = (A0 + REG);
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_addq_A0,REGNAME),_s1)(void)
|
||||
{
|
||||
A0 = (A0 + (REG << 1));
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_addq_A0,REGNAME),_s2)(void)
|
||||
{
|
||||
A0 = (A0 + (REG << 2));
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_addq_A0,REGNAME),_s3)(void)
|
||||
{
|
||||
A0 = (A0 + (REG << 3));
|
||||
}
|
||||
#endif
|
||||
|
||||
void OPPROTO glue(op_movl_T0,REGNAME)(void)
|
||||
{
|
||||
T0 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_movl_T1,REGNAME)(void)
|
||||
{
|
||||
T1 = REG;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_movh_T0,REGNAME)(void)
|
||||
{
|
||||
T0 = REG >> 8;
|
||||
}
|
||||
|
||||
void OPPROTO glue(op_movh_T1,REGNAME)(void)
|
||||
{
|
||||
T1 = REG >> 8;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_movl,REGNAME),_T0)(void)
|
||||
{
|
||||
REG = (uint32_t)T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_movl,REGNAME),_T1)(void)
|
||||
{
|
||||
REG = (uint32_t)T1;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void)
|
||||
{
|
||||
REG = (uint32_t)A0;
|
||||
}
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
void OPPROTO glue(glue(op_movq,REGNAME),_T0)(void)
|
||||
{
|
||||
REG = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_movq,REGNAME),_T1)(void)
|
||||
{
|
||||
REG = T1;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_movq,REGNAME),_A0)(void)
|
||||
{
|
||||
REG = A0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* mov T1 to REG if T0 is true */
|
||||
void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void)
|
||||
{
|
||||
@ -132,8 +28,15 @@ void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void)
|
||||
|
||||
void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void)
|
||||
{
|
||||
#ifdef TARGET_X86_64
|
||||
if (T0)
|
||||
REG = (uint32_t)T1;
|
||||
else
|
||||
REG = (uint32_t)REG;
|
||||
#else
|
||||
if (T0)
|
||||
REG = (uint32_t)T1;
|
||||
#endif
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
@ -145,46 +48,3 @@ void OPPROTO glue(glue(op_cmovq,REGNAME),_T1_T0)(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* NOTE: T0 high order bits are ignored */
|
||||
void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void)
|
||||
{
|
||||
REG = (REG & ~0xffff) | (T0 & 0xffff);
|
||||
}
|
||||
|
||||
/* NOTE: T0 high order bits are ignored */
|
||||
void OPPROTO glue(glue(op_movw,REGNAME),_T1)(void)
|
||||
{
|
||||
REG = (REG & ~0xffff) | (T1 & 0xffff);
|
||||
}
|
||||
|
||||
/* NOTE: A0 high order bits are ignored */
|
||||
void OPPROTO glue(glue(op_movw,REGNAME),_A0)(void)
|
||||
{
|
||||
REG = (REG & ~0xffff) | (A0 & 0xffff);
|
||||
}
|
||||
|
||||
/* NOTE: T0 high order bits are ignored */
|
||||
void OPPROTO glue(glue(op_movb,REGNAME),_T0)(void)
|
||||
{
|
||||
REG = (REG & ~0xff) | (T0 & 0xff);
|
||||
}
|
||||
|
||||
/* NOTE: T0 high order bits are ignored */
|
||||
void OPPROTO glue(glue(op_movh,REGNAME),_T0)(void)
|
||||
{
|
||||
REG = (REG & ~0xff00) | ((T0 & 0xff) << 8);
|
||||
}
|
||||
|
||||
/* NOTE: T1 high order bits are ignored */
|
||||
void OPPROTO glue(glue(op_movb,REGNAME),_T1)(void)
|
||||
{
|
||||
REG = (REG & ~0xff) | (T1 & 0xff);
|
||||
}
|
||||
|
||||
/* NOTE: T1 high order bits are ignored */
|
||||
void OPPROTO glue(glue(op_movh,REGNAME),_T1)(void)
|
||||
{
|
||||
REG = (REG & ~0xff00) | ((T1 & 0xff) << 8);
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -482,7 +482,7 @@ OP(set_sr)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
OP(jmp)
|
||||
OP(jmp_im)
|
||||
{
|
||||
GOTO_LABEL_PARAM(1);
|
||||
}
|
||||
@ -522,22 +522,6 @@ OP(jmp_T0)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_goto_tb0(void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb0, PARAM1, 0);
|
||||
}
|
||||
|
||||
void OPPROTO op_goto_tb1(void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb1, PARAM1, 1);
|
||||
}
|
||||
|
||||
OP(exit_tb)
|
||||
{
|
||||
EXIT_TB();
|
||||
}
|
||||
|
||||
|
||||
/* Floating point. */
|
||||
OP(f64_to_i32)
|
||||
{
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
#include "tcg-op.h"
|
||||
#include "m68k-qreg.h"
|
||||
|
||||
//#define DEBUG_DISPATCH 1
|
||||
@ -67,20 +68,9 @@ typedef struct DisasContext {
|
||||
static void *gen_throws_exception;
|
||||
#define gen_last_qop NULL
|
||||
|
||||
static uint16_t *gen_opc_ptr;
|
||||
static uint32_t *gen_opparam_ptr;
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#include "gen-op.h"
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#define gen_st(s, name, addr, val) gen_op_st##name##_raw(addr, val)
|
||||
#define gen_ld(s, name, val, addr) gen_op_ld##name##_raw(val, addr)
|
||||
@ -622,7 +612,7 @@ static void gen_jmpcc(DisasContext *s, int cond, int l1)
|
||||
gen_flush_flags(s);
|
||||
switch (cond) {
|
||||
case 0: /* T */
|
||||
gen_op_jmp(l1);
|
||||
gen_op_jmp_im(l1);
|
||||
break;
|
||||
case 1: /* F */
|
||||
break;
|
||||
@ -702,7 +692,7 @@ static void gen_jmpcc(DisasContext *s, int cond, int l1)
|
||||
gen_op_xor32(tmp, tmp, QREG_CC_DEST);
|
||||
gen_op_and32(tmp, tmp, gen_im32(CCF_V));
|
||||
gen_op_jmp_nz32(tmp, l2);
|
||||
gen_op_jmp(l1);
|
||||
gen_op_jmp_im(l1);
|
||||
gen_set_label(l2);
|
||||
}
|
||||
break;
|
||||
@ -791,14 +781,12 @@ static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
|
||||
gen_exception(s, dest, EXCP_DEBUG);
|
||||
} else if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) ||
|
||||
(s->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
|
||||
gen_op_goto_tb(0, n, (long)tb);
|
||||
tcg_gen_goto_tb(n);
|
||||
gen_op_mov32(QREG_PC, gen_im32(dest));
|
||||
gen_op_mov32(QREG_T0, gen_im32((long)tb + n));
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb((long)tb + n);
|
||||
} else {
|
||||
gen_jmp(s, gen_im32(dest));
|
||||
gen_op_mov32(QREG_T0, gen_im32(0));
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
}
|
||||
s->is_jmp = DISAS_TB_JUMP;
|
||||
}
|
||||
@ -3073,7 +3061,7 @@ static void expand_op_addx_cc(qOP *qop)
|
||||
gen_op_add32(arg0, arg0, gen_im32(1));
|
||||
gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_ADDX));
|
||||
gen_op_set_leu32(QREG_CC_X, arg0, arg1);
|
||||
gen_op_jmp(l2);
|
||||
gen_op_jmp_im(l2);
|
||||
gen_set_label(l1);
|
||||
gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_ADD));
|
||||
gen_op_set_ltu32(QREG_CC_X, arg0, arg1);
|
||||
@ -3093,7 +3081,7 @@ static void expand_op_subx_cc(qOP *qop)
|
||||
gen_op_set_leu32(QREG_CC_X, arg0, arg1);
|
||||
gen_op_sub32(arg0, arg0, gen_im32(1));
|
||||
gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_SUBX));
|
||||
gen_op_jmp(l2);
|
||||
gen_op_jmp_im(l2);
|
||||
gen_set_label(l1);
|
||||
gen_op_set_ltu32(QREG_CC_X, arg0, arg1);
|
||||
gen_op_mov32(QREG_CC_OP, gen_im32(CC_OP_SUB));
|
||||
@ -3162,9 +3150,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
||||
|
||||
dc->tb = tb;
|
||||
|
||||
gen_opc_ptr = gen_opc_buf;
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
|
||||
dc->env = env;
|
||||
dc->is_jmp = DISAS_NEXT;
|
||||
@ -3174,7 +3160,6 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
||||
dc->fpcr = env->fpcr;
|
||||
dc->user = (env->sr & SR_S) == 0;
|
||||
dc->is_mem = 0;
|
||||
nb_gen_labels = 0;
|
||||
lj = -1;
|
||||
do {
|
||||
free_qreg = 0;
|
||||
@ -3232,8 +3217,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
||||
case DISAS_UPDATE:
|
||||
gen_flush_cc_op(dc);
|
||||
/* indicate that the hash table must be used to find the next TB */
|
||||
gen_op_mov32(QREG_T0, gen_im32(0));
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
break;
|
||||
case DISAS_TB_JUMP:
|
||||
/* nothing more to generate */
|
||||
@ -3248,11 +3232,6 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
|
||||
target_disas(logfile, pc_start, dc->pc - pc_start, 0);
|
||||
fprintf(logfile, "\n");
|
||||
if (loglevel & (CPU_LOG_TB_OP)) {
|
||||
fprintf(logfile, "OP:\n");
|
||||
dump_ops(gen_opc_buf, gen_opparam_buf);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (search_pc) {
|
||||
|
@ -1093,18 +1093,6 @@ OP_COND(lez, (target_long)T0 <= 0);
|
||||
OP_COND(ltz, (target_long)T0 < 0);
|
||||
|
||||
/* Branches */
|
||||
void OPPROTO op_goto_tb0(void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb0, PARAM1, 0);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO op_goto_tb1(void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb1, PARAM1, 1);
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
/* Branch to register */
|
||||
void op_save_breg_target (void)
|
||||
{
|
||||
@ -3252,12 +3240,6 @@ void op_raise_exception_err (void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void op_exit_tb (void)
|
||||
{
|
||||
EXIT_TB();
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void op_wait (void)
|
||||
{
|
||||
env->halted = 1;
|
||||
|
@ -29,29 +29,12 @@
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
#include "tcg-op.h"
|
||||
|
||||
//#define MIPS_DEBUG_DISAS
|
||||
//#define MIPS_DEBUG_SIGN_EXTENSIONS
|
||||
//#define MIPS_SINGLE_STEP
|
||||
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
#define TBPARAM(x)
|
||||
#else
|
||||
#define TBPARAM(x) (long)(x)
|
||||
#endif
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
static uint16_t *gen_opc_ptr;
|
||||
static uint32_t *gen_opparam_ptr;
|
||||
|
||||
#include "gen-op.h"
|
||||
|
||||
/* MIPS major opcodes */
|
||||
#define MASK_OP_MAJOR(op) (op & (0x3F << 26))
|
||||
|
||||
@ -1777,17 +1760,13 @@ static always_inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong des
|
||||
TranslationBlock *tb;
|
||||
tb = ctx->tb;
|
||||
if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
|
||||
if (n == 0)
|
||||
gen_op_goto_tb0(TBPARAM(tb));
|
||||
else
|
||||
gen_op_goto_tb1(TBPARAM(tb));
|
||||
tcg_gen_goto_tb(n);
|
||||
gen_save_pc(dest);
|
||||
gen_op_set_T0((long)tb + n);
|
||||
tcg_gen_exit_tb((long)tb + n);
|
||||
} else {
|
||||
gen_save_pc(dest);
|
||||
gen_op_reset_T0();
|
||||
tcg_gen_exit_tb(0);
|
||||
}
|
||||
gen_op_exit_tb();
|
||||
}
|
||||
|
||||
/* Branches (before delay slot) */
|
||||
@ -6642,8 +6621,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
|
||||
/* unconditional branch to register */
|
||||
MIPS_DEBUG("branch to register");
|
||||
gen_op_breg();
|
||||
gen_op_reset_T0();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
break;
|
||||
default:
|
||||
MIPS_DEBUG("unknown branch");
|
||||
@ -6665,10 +6643,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
|
||||
fprintf (logfile, "search pc %d\n", search_pc);
|
||||
|
||||
pc_start = tb->pc;
|
||||
gen_opc_ptr = gen_opc_buf;
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
nb_gen_labels = 0;
|
||||
ctx.pc = pc_start;
|
||||
ctx.saved_pc = -1;
|
||||
ctx.tb = tb;
|
||||
@ -6748,8 +6723,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
|
||||
break;
|
||||
case BS_EXCP:
|
||||
gen_op_interrupt_restart();
|
||||
gen_op_reset_T0();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
break;
|
||||
case BS_BRANCH:
|
||||
default:
|
||||
@ -6777,11 +6751,6 @@ done_generating:
|
||||
target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
if (loglevel & CPU_LOG_TB_OP) {
|
||||
fprintf(logfile, "OP:\n");
|
||||
dump_ops(gen_opc_buf, gen_opparam_buf);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
if (loglevel & CPU_LOG_TB_CPU) {
|
||||
fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags);
|
||||
}
|
||||
|
@ -222,11 +222,6 @@ void OPPROTO op_debug (void)
|
||||
do_raise_exception(EXCP_DEBUG);
|
||||
}
|
||||
|
||||
void OPPROTO op_exit_tb (void)
|
||||
{
|
||||
EXIT_TB();
|
||||
}
|
||||
|
||||
/* Load/store special registers */
|
||||
void OPPROTO op_load_cr (void)
|
||||
{
|
||||
@ -674,16 +669,6 @@ void OPPROTO op_setlr_64 (void)
|
||||
}
|
||||
#endif
|
||||
|
||||
void OPPROTO op_goto_tb0 (void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb0, PARAM1, 0);
|
||||
}
|
||||
|
||||
void OPPROTO op_goto_tb1 (void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb1, PARAM1, 1);
|
||||
}
|
||||
|
||||
void OPPROTO op_b_T1 (void)
|
||||
{
|
||||
env->nip = (uint32_t)(T1 & ~3);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
#include "tcg-op.h"
|
||||
|
||||
/* Include definitions for instructions classes and implementations flags */
|
||||
//#define DO_SINGLE_STEP
|
||||
@ -36,28 +37,12 @@
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code translation helpers */
|
||||
#if defined(USE_DIRECT_JUMP)
|
||||
#define TBPARAM(x)
|
||||
#else
|
||||
#define TBPARAM(x) (long)(x)
|
||||
#endif
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
static uint16_t *gen_opc_ptr;
|
||||
static uint32_t *gen_opparam_ptr;
|
||||
#if defined(OPTIMIZE_FPRF_UPDATE)
|
||||
static uint16_t *gen_fprf_buf[OPC_BUF_SIZE];
|
||||
static uint16_t **gen_fprf_ptr;
|
||||
#endif
|
||||
|
||||
#include "gen-op.h"
|
||||
|
||||
static always_inline void gen_set_T0 (target_ulong val)
|
||||
{
|
||||
#if defined(TARGET_PPC64)
|
||||
@ -2798,11 +2783,9 @@ static always_inline void gen_goto_tb (DisasContext *ctx, int n,
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
tb = ctx->tb;
|
||||
if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
|
||||
if (n == 0)
|
||||
gen_op_goto_tb0(TBPARAM(tb));
|
||||
else
|
||||
gen_op_goto_tb1(TBPARAM(tb));
|
||||
if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
|
||||
!ctx->singlestep_enabled) {
|
||||
tcg_gen_goto_tb(n);
|
||||
gen_set_T1(dest);
|
||||
#if defined(TARGET_PPC64)
|
||||
if (ctx->sf_mode)
|
||||
@ -2810,10 +2793,7 @@ static always_inline void gen_goto_tb (DisasContext *ctx, int n,
|
||||
else
|
||||
#endif
|
||||
gen_op_b_T1();
|
||||
gen_op_set_T0((long)tb + n);
|
||||
if (ctx->singlestep_enabled)
|
||||
gen_op_debug();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb((long)tb + n);
|
||||
} else {
|
||||
gen_set_T1(dest);
|
||||
#if defined(TARGET_PPC64)
|
||||
@ -2822,10 +2802,9 @@ static always_inline void gen_goto_tb (DisasContext *ctx, int n,
|
||||
else
|
||||
#endif
|
||||
gen_op_b_T1();
|
||||
gen_op_reset_T0();
|
||||
if (ctx->singlestep_enabled)
|
||||
gen_op_debug();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2934,7 +2913,6 @@ static always_inline void gen_bcond (DisasContext *ctx, int type)
|
||||
else
|
||||
#endif
|
||||
gen_op_b_T1();
|
||||
gen_op_reset_T0();
|
||||
goto no_test;
|
||||
}
|
||||
break;
|
||||
@ -3005,11 +2983,10 @@ static always_inline void gen_bcond (DisasContext *ctx, int type)
|
||||
else
|
||||
#endif
|
||||
gen_op_btest_T1(ctx->nip);
|
||||
gen_op_reset_T0();
|
||||
no_test:
|
||||
if (ctx->singlestep_enabled)
|
||||
gen_op_debug();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
}
|
||||
out:
|
||||
ctx->exception = POWERPC_EXCP_BRANCH;
|
||||
@ -6176,13 +6153,10 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
|
||||
int j, lj = -1;
|
||||
|
||||
pc_start = tb->pc;
|
||||
gen_opc_ptr = gen_opc_buf;
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
#if defined(OPTIMIZE_FPRF_UPDATE)
|
||||
gen_fprf_ptr = gen_fprf_buf;
|
||||
#endif
|
||||
nb_gen_labels = 0;
|
||||
ctx.nip = pc_start;
|
||||
ctx.tb = tb;
|
||||
ctx.exception = POWERPC_EXCP_NONE;
|
||||
@ -6332,9 +6306,8 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
|
||||
if (ctx.exception == POWERPC_EXCP_NONE) {
|
||||
gen_goto_tb(&ctx, 0, ctx.nip);
|
||||
} else if (ctx.exception != POWERPC_EXCP_BRANCH) {
|
||||
gen_op_reset_T0();
|
||||
/* Generate the return instruction */
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
}
|
||||
*gen_opc_ptr = INDEX_op_end;
|
||||
if (unlikely(search_pc)) {
|
||||
@ -6358,11 +6331,6 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
|
||||
target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
if (loglevel & CPU_LOG_TB_OP) {
|
||||
fprintf(logfile, "OP:\n");
|
||||
dump_ops(gen_opc_buf, gen_opparam_buf);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -161,12 +161,6 @@ void OPPROTO op_rts(void)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_exit_tb(void)
|
||||
{
|
||||
EXIT_TB();
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_addl_imm_T0(void)
|
||||
{
|
||||
T0 += PARAM1;
|
||||
@ -947,18 +941,6 @@ void OPPROTO op_movl_FT0_fpul(void)
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_goto_tb0(void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb0, PARAM1, 0);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_goto_tb1(void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb1, PARAM1, 1);
|
||||
RETURN();
|
||||
}
|
||||
|
||||
void OPPROTO op_movl_imm_PC(void)
|
||||
{
|
||||
env->pc = PARAM1;
|
||||
|
@ -31,24 +31,7 @@
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
#define TBPARAM(x)
|
||||
#else
|
||||
#define TBPARAM(x) ((long)(x))
|
||||
#endif
|
||||
|
||||
static uint16_t *gen_opc_ptr;
|
||||
static uint32_t *gen_opparam_ptr;
|
||||
|
||||
#include "gen-op.h"
|
||||
#include "tcg-op.h"
|
||||
|
||||
typedef struct DisasContext {
|
||||
struct TranslationBlock *tb;
|
||||
@ -172,18 +155,15 @@ static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest)
|
||||
if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
|
||||
!ctx->singlestep_enabled) {
|
||||
/* Use a direct jump if in same page and singlestep not enabled */
|
||||
if (n == 0)
|
||||
gen_op_goto_tb0(TBPARAM(tb));
|
||||
else
|
||||
gen_op_goto_tb1(TBPARAM(tb));
|
||||
gen_op_movl_imm_T0((long) tb + n);
|
||||
tcg_gen_goto_tb(n);
|
||||
gen_op_movl_imm_PC(dest);
|
||||
tcg_gen_exit_tb((long) tb + n);
|
||||
} else {
|
||||
gen_op_movl_imm_T0(0);
|
||||
gen_op_movl_imm_PC(dest);
|
||||
if (ctx->singlestep_enabled)
|
||||
gen_op_debug();
|
||||
tcg_gen_exit_tb(0);
|
||||
}
|
||||
gen_op_movl_imm_PC(dest);
|
||||
if (ctx->singlestep_enabled)
|
||||
gen_op_debug();
|
||||
gen_op_exit_tb();
|
||||
}
|
||||
|
||||
static void gen_jump(DisasContext * ctx)
|
||||
@ -192,10 +172,9 @@ static void gen_jump(DisasContext * ctx)
|
||||
/* Target is not statically known, it comes necessarily from a
|
||||
delayed jump as immediate jump are conditinal jumps */
|
||||
gen_op_movl_delayed_pc_PC();
|
||||
gen_op_movl_imm_T0(0);
|
||||
if (ctx->singlestep_enabled)
|
||||
gen_op_debug();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
} else {
|
||||
gen_goto_tb(ctx, 0, ctx->delayed_pc);
|
||||
}
|
||||
@ -1176,9 +1155,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
|
||||
int i, ii;
|
||||
|
||||
pc_start = tb->pc;
|
||||
gen_opc_ptr = gen_opc_buf;
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
ctx.pc = pc_start;
|
||||
ctx.flags = (uint32_t)tb->flags;
|
||||
ctx.bstate = BS_NONE;
|
||||
@ -1190,7 +1167,6 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
|
||||
ctx.delayed_pc = -1; /* use delayed pc from env pointer */
|
||||
ctx.tb = tb;
|
||||
ctx.singlestep_enabled = env->singlestep_enabled;
|
||||
nb_gen_labels = 0;
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
if (loglevel & CPU_LOG_TB_CPU) {
|
||||
@ -1254,8 +1230,7 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
|
||||
break;
|
||||
case BS_EXCP:
|
||||
/* gen_op_interrupt_restart(); */
|
||||
gen_op_movl_imm_T0(0);
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
break;
|
||||
case BS_BRANCH:
|
||||
default:
|
||||
@ -1283,11 +1258,6 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
|
||||
target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
if (loglevel & CPU_LOG_TB_OP) {
|
||||
fprintf(logfile, "OP:\n");
|
||||
dump_ops(gen_opc_buf, gen_opparam_buf);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -1277,11 +1277,6 @@ void OPPROTO op_debug(void)
|
||||
helper_debug();
|
||||
}
|
||||
|
||||
void OPPROTO op_exit_tb(void)
|
||||
{
|
||||
EXIT_TB();
|
||||
}
|
||||
|
||||
void OPPROTO op_eval_ba(void)
|
||||
{
|
||||
T2 = 1;
|
||||
@ -1542,16 +1537,6 @@ void OPPROTO op_next_insn(void)
|
||||
env->npc = env->npc + 4;
|
||||
}
|
||||
|
||||
void OPPROTO op_goto_tb0(void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb0, PARAM1, 0);
|
||||
}
|
||||
|
||||
void OPPROTO op_goto_tb1(void)
|
||||
{
|
||||
GOTO_TB(op_goto_tb1, PARAM1, 1);
|
||||
}
|
||||
|
||||
void OPPROTO op_jmp_label(void)
|
||||
{
|
||||
GOTO_LABEL_PARAM(1);
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
#include "tcg-op.h"
|
||||
|
||||
#define DEBUG_DISAS
|
||||
|
||||
@ -65,20 +66,9 @@ struct sparc_def_t {
|
||||
|
||||
static const sparc_def_t *cpu_sparc_find_by_name(const unsigned char *name);
|
||||
|
||||
static uint16_t *gen_opc_ptr;
|
||||
static uint32_t *gen_opparam_ptr;
|
||||
extern FILE *logfile;
|
||||
extern int loglevel;
|
||||
|
||||
enum {
|
||||
#define DEF(s,n,copy_size) INDEX_op_ ## s,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS
|
||||
};
|
||||
|
||||
#include "gen-op.h"
|
||||
|
||||
// This function uses non-native bit order
|
||||
#define GET_FIELD(X, FROM, TO) \
|
||||
((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1))
|
||||
@ -98,12 +88,6 @@ enum {
|
||||
#define QFPREG(r) (r & 0x1c)
|
||||
#endif
|
||||
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
#define TBPARAM(x)
|
||||
#else
|
||||
#define TBPARAM(x) (long)(x)
|
||||
#endif
|
||||
|
||||
static int sign_extend(int x, int len)
|
||||
{
|
||||
len = 32 - len;
|
||||
@ -699,20 +683,15 @@ static inline void gen_goto_tb(DisasContext *s, int tb_num,
|
||||
if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) &&
|
||||
(npc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK)) {
|
||||
/* jump to same page: we can use a direct jump */
|
||||
if (tb_num == 0)
|
||||
gen_op_goto_tb0(TBPARAM(tb));
|
||||
else
|
||||
gen_op_goto_tb1(TBPARAM(tb));
|
||||
tcg_gen_goto_tb(tb_num);
|
||||
gen_jmp_im(pc);
|
||||
gen_movl_npc_im(npc);
|
||||
gen_op_movl_T0_im((long)tb + tb_num);
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb((long)tb + tb_num);
|
||||
} else {
|
||||
/* jump to another page: currently not optimized */
|
||||
gen_jmp_im(pc);
|
||||
gen_movl_npc_im(npc);
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1281,8 +1260,7 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||
gen_op_trapcc_T0();
|
||||
}
|
||||
gen_op_next_insn();
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
dc->is_br = 1;
|
||||
goto jmp_insn;
|
||||
} else if (xop == 0x28) {
|
||||
@ -2341,8 +2319,7 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||
gen_op_movl_env_T0(offsetof(CPUSPARCState, fprs));
|
||||
save_state(dc);
|
||||
gen_op_next_insn();
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
dc->is_br = 1;
|
||||
break;
|
||||
case 0xf: /* V9 sir, nop if user */
|
||||
@ -2422,8 +2399,7 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||
gen_op_wrpsr();
|
||||
save_state(dc);
|
||||
gen_op_next_insn();
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
dc->is_br = 1;
|
||||
#endif
|
||||
}
|
||||
@ -2457,8 +2433,7 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||
gen_op_wrpstate();
|
||||
save_state(dc);
|
||||
gen_op_next_insn();
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
dc->is_br = 1;
|
||||
break;
|
||||
case 7: // tl
|
||||
@ -2517,8 +2492,7 @@ static void disas_sparc_insn(DisasContext * dc)
|
||||
// XXX gen_op_wrhpstate();
|
||||
save_state(dc);
|
||||
gen_op_next_insn();
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
dc->is_br = 1;
|
||||
break;
|
||||
case 1: // htstate
|
||||
@ -3635,10 +3609,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
||||
dc->npc = (target_ulong) tb->cs_base;
|
||||
dc->mem_idx = cpu_mmu_index(env);
|
||||
dc->fpu_enabled = cpu_fpu_enabled(env);
|
||||
gen_opc_ptr = gen_opc_buf;
|
||||
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
|
||||
gen_opparam_ptr = gen_opparam_buf;
|
||||
nb_gen_labels = 0;
|
||||
|
||||
do {
|
||||
if (env->nb_breakpoints > 0) {
|
||||
@ -3647,8 +3618,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
||||
if (dc->pc != pc_start)
|
||||
save_state(dc);
|
||||
gen_op_debug();
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
dc->is_br = 1;
|
||||
goto exit_gen_loop;
|
||||
}
|
||||
@ -3683,8 +3653,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
||||
generate an exception */
|
||||
if (env->singlestep_enabled) {
|
||||
gen_jmp_im(dc->pc);
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
break;
|
||||
}
|
||||
} while ((gen_opc_ptr < gen_opc_end) &&
|
||||
@ -3700,8 +3669,7 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
||||
if (dc->pc != DYNAMIC_PC)
|
||||
gen_jmp_im(dc->pc);
|
||||
save_npc(dc);
|
||||
gen_op_movl_T0_0();
|
||||
gen_op_exit_tb();
|
||||
tcg_gen_exit_tb(0);
|
||||
}
|
||||
}
|
||||
*gen_opc_ptr = INDEX_op_end;
|
||||
@ -3726,11 +3694,6 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
|
||||
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
|
||||
target_disas(logfile, pc_start, last_pc + 4 - pc_start, 0);
|
||||
fprintf(logfile, "\n");
|
||||
if (loglevel & CPU_LOG_TB_OP) {
|
||||
fprintf(logfile, "OP:\n");
|
||||
dump_ops(gen_opc_buf, gen_opparam_buf);
|
||||
fprintf(logfile, "\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
@ -3746,8 +3709,6 @@ int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
|
||||
return gen_intermediate_code_internal(tb, 1, env);
|
||||
}
|
||||
|
||||
extern int ram_size;
|
||||
|
||||
void cpu_reset(CPUSPARCState *env)
|
||||
{
|
||||
tlb_flush(env, 1);
|
||||
|
196
translate-all.c
196
translate-all.c
@ -29,22 +29,13 @@
|
||||
#include "cpu.h"
|
||||
#include "exec-all.h"
|
||||
#include "disas.h"
|
||||
#include "tcg.h"
|
||||
|
||||
extern int dyngen_code(uint8_t *gen_code_buf,
|
||||
uint16_t *label_offsets, uint16_t *jmp_offsets,
|
||||
const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels);
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
/* code generation context */
|
||||
TCGContext tcg_ctx;
|
||||
|
||||
uint16_t gen_opc_buf[OPC_BUF_SIZE];
|
||||
uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
long gen_labels[OPC_BUF_SIZE];
|
||||
int nb_gen_labels;
|
||||
TCGArg gen_opparam_buf[OPPARAM_BUF_SIZE];
|
||||
|
||||
target_ulong gen_opc_pc[OPC_BUF_SIZE];
|
||||
uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
|
||||
@ -59,86 +50,29 @@ uint32_t gen_opc_hflags[OPC_BUF_SIZE];
|
||||
|
||||
int code_copy_enabled = 1;
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
static const char *op_str[] = {
|
||||
#define DEF(s, n, copy_size) #s,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
static uint8_t op_nb_args[] = {
|
||||
#define DEF(s, n, copy_size) n,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
static const unsigned short opc_copy_size[] = {
|
||||
#define DEF(s, n, copy_size) copy_size,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
};
|
||||
|
||||
void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
|
||||
{
|
||||
const uint16_t *opc_ptr;
|
||||
const uint32_t *opparam_ptr;
|
||||
int c, n, i;
|
||||
|
||||
opc_ptr = opc_buf;
|
||||
opparam_ptr = opparam_buf;
|
||||
for(;;) {
|
||||
c = *opc_ptr++;
|
||||
n = op_nb_args[c];
|
||||
fprintf(logfile, "0x%04x: %s",
|
||||
(int)(opc_ptr - opc_buf - 1), op_str[c]);
|
||||
for(i = 0; i < n; i++) {
|
||||
fprintf(logfile, " 0x%x", opparam_ptr[i]);
|
||||
}
|
||||
fprintf(logfile, "\n");
|
||||
if (c == INDEX_op_end)
|
||||
break;
|
||||
opparam_ptr += n;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROFILER
|
||||
int64_t dyngen_tb_count1;
|
||||
int64_t dyngen_tb_count;
|
||||
int64_t dyngen_op_count;
|
||||
int64_t dyngen_old_op_count;
|
||||
int64_t dyngen_tcg_del_op_count;
|
||||
int dyngen_op_count_max;
|
||||
int64_t dyngen_code_in_len;
|
||||
int64_t dyngen_code_out_len;
|
||||
int64_t dyngen_interm_time;
|
||||
int64_t dyngen_code_time;
|
||||
int64_t dyngen_restore_count;
|
||||
int64_t dyngen_restore_time;
|
||||
#endif
|
||||
|
||||
/* compute label info */
|
||||
static void dyngen_labels(long *gen_labels, int nb_gen_labels,
|
||||
uint8_t *gen_code_buf, const uint16_t *opc_buf)
|
||||
{
|
||||
uint8_t *gen_code_ptr;
|
||||
int c, i;
|
||||
unsigned long gen_code_addr[OPC_BUF_SIZE];
|
||||
|
||||
if (nb_gen_labels == 0)
|
||||
return;
|
||||
/* compute the address of each op code */
|
||||
|
||||
gen_code_ptr = gen_code_buf;
|
||||
i = 0;
|
||||
for(;;) {
|
||||
c = opc_buf[i];
|
||||
gen_code_addr[i] =(unsigned long)gen_code_ptr;
|
||||
if (c == INDEX_op_end)
|
||||
break;
|
||||
gen_code_ptr += opc_copy_size[c];
|
||||
i++;
|
||||
}
|
||||
|
||||
/* compute the address of each label */
|
||||
for(i = 0; i < nb_gen_labels; i++) {
|
||||
gen_labels[i] = gen_code_addr[gen_labels[i]];
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX: suppress that */
|
||||
unsigned long code_gen_max_block_size(void)
|
||||
{
|
||||
static unsigned long max;
|
||||
|
||||
if (max == 0) {
|
||||
#define DEF(s, n, copy_size) max = copy_size > max? copy_size : max;
|
||||
#include "opc.h"
|
||||
#include "tcg-opc.h"
|
||||
#undef DEF
|
||||
max *= OPC_MAX_SIZE;
|
||||
}
|
||||
@ -146,6 +80,13 @@ unsigned long code_gen_max_block_size(void)
|
||||
return max;
|
||||
}
|
||||
|
||||
void cpu_gen_init(void)
|
||||
{
|
||||
tcg_context_init(&tcg_ctx);
|
||||
tcg_set_frame(&tcg_ctx, TCG_AREG0, offsetof(CPUState, temp_buf),
|
||||
128 * sizeof(long));
|
||||
}
|
||||
|
||||
/* return non zero if the very first instruction is invalid so that
|
||||
the virtual CPU can trigger an exception.
|
||||
|
||||
@ -154,31 +95,53 @@ unsigned long code_gen_max_block_size(void)
|
||||
*/
|
||||
int cpu_gen_code(CPUState *env, TranslationBlock *tb, int *gen_code_size_ptr)
|
||||
{
|
||||
TCGContext *s = &tcg_ctx;
|
||||
uint8_t *gen_code_buf;
|
||||
int gen_code_size;
|
||||
#ifdef CONFIG_PROFILER
|
||||
int64_t ti;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PROFILER
|
||||
dyngen_tb_count1++; /* includes aborted translations because of
|
||||
exceptions */
|
||||
ti = profile_getclock();
|
||||
#endif
|
||||
tcg_func_start(s);
|
||||
|
||||
if (gen_intermediate_code(env, tb) < 0)
|
||||
return -1;
|
||||
|
||||
/* generate machine code */
|
||||
gen_code_buf = tb->tc_ptr;
|
||||
tb->tb_next_offset[0] = 0xffff;
|
||||
tb->tb_next_offset[1] = 0xffff;
|
||||
gen_code_buf = tb->tc_ptr;
|
||||
s->tb_next_offset = tb->tb_next_offset;
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
s->tb_jmp_offset = tb->tb_jmp_offset;
|
||||
s->tb_next = NULL;
|
||||
/* the following two entries are optional (only used for string ops) */
|
||||
/* XXX: not used ? */
|
||||
tb->tb_jmp_offset[2] = 0xffff;
|
||||
tb->tb_jmp_offset[3] = 0xffff;
|
||||
#endif
|
||||
dyngen_labels(gen_labels, nb_gen_labels, gen_code_buf, gen_opc_buf);
|
||||
|
||||
gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
tb->tb_jmp_offset,
|
||||
#else
|
||||
NULL,
|
||||
s->tb_jmp_offset = NULL;
|
||||
s->tb_next = tb->tb_next;
|
||||
#endif
|
||||
gen_opc_buf, gen_opparam_buf, gen_labels);
|
||||
|
||||
#ifdef CONFIG_PROFILER
|
||||
dyngen_tb_count++;
|
||||
dyngen_interm_time += profile_getclock() - ti;
|
||||
dyngen_code_time -= profile_getclock();
|
||||
#endif
|
||||
gen_code_size = dyngen_code(s, gen_code_buf);
|
||||
*gen_code_size_ptr = gen_code_size;
|
||||
#ifdef CONFIG_PROFILER
|
||||
dyngen_code_time += profile_getclock();
|
||||
dyngen_code_in_len += tb->size;
|
||||
dyngen_code_out_len += gen_code_size;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
if (loglevel & CPU_LOG_TB_OUT_ASM) {
|
||||
fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
|
||||
@ -196,9 +159,17 @@ int cpu_restore_state(TranslationBlock *tb,
|
||||
CPUState *env, unsigned long searched_pc,
|
||||
void *puc)
|
||||
{
|
||||
int j, c;
|
||||
TCGContext *s = &tcg_ctx;
|
||||
int j;
|
||||
unsigned long tc_ptr;
|
||||
uint16_t *opc_ptr;
|
||||
#ifdef CONFIG_PROFILER
|
||||
int64_t ti;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PROFILER
|
||||
ti = profile_getclock();
|
||||
#endif
|
||||
tcg_func_start(s);
|
||||
|
||||
if (gen_intermediate_code_pc(env, tb) < 0)
|
||||
return -1;
|
||||
@ -207,18 +178,19 @@ int cpu_restore_state(TranslationBlock *tb,
|
||||
tc_ptr = (unsigned long)tb->tc_ptr;
|
||||
if (searched_pc < tc_ptr)
|
||||
return -1;
|
||||
j = 0;
|
||||
opc_ptr = gen_opc_buf;
|
||||
for(;;) {
|
||||
c = *opc_ptr;
|
||||
if (c == INDEX_op_end)
|
||||
return -1;
|
||||
tc_ptr += opc_copy_size[c];
|
||||
if (searched_pc < tc_ptr)
|
||||
break;
|
||||
opc_ptr++;
|
||||
}
|
||||
j = opc_ptr - gen_opc_buf;
|
||||
|
||||
s->tb_next_offset = tb->tb_next_offset;
|
||||
#ifdef USE_DIRECT_JUMP
|
||||
s->tb_jmp_offset = tb->tb_jmp_offset;
|
||||
s->tb_next = NULL;
|
||||
#else
|
||||
s->tb_jmp_offset = NULL;
|
||||
s->tb_next = tb->tb_next;
|
||||
#endif
|
||||
j = dyngen_code_search_pc(s, (uint8_t *)tc_ptr,
|
||||
(void *)searched_pc);
|
||||
if (j < 0)
|
||||
return -1;
|
||||
/* now find start of instruction before */
|
||||
while (gen_opc_instr_start[j] == 0)
|
||||
j--;
|
||||
@ -266,10 +238,11 @@ int cpu_restore_state(TranslationBlock *tb,
|
||||
}
|
||||
#elif defined(TARGET_PPC)
|
||||
{
|
||||
int type;
|
||||
int type, c;
|
||||
/* for PPC, we need to look at the micro operation to get the
|
||||
access type */
|
||||
env->nip = gen_opc_pc[j];
|
||||
c = gen_opc_buf[j];
|
||||
switch(c) {
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#define CASE3(op)\
|
||||
@ -315,5 +288,10 @@ int cpu_restore_state(TranslationBlock *tb,
|
||||
env->pc = gen_opc_pc[j];
|
||||
env->flags = gen_opc_hflags[j];
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PROFILER
|
||||
dyngen_restore_time += profile_getclock() - ti;
|
||||
dyngen_restore_count++;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Host code generation
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "osdep.h"
|
||||
|
||||
enum {
|
||||
#define DEF(s, n, copy_size) INDEX_op_ ## s,
|
||||
#include "opc.h"
|
||||
#undef DEF
|
||||
NB_OPS,
|
||||
};
|
||||
|
||||
#include "dyngen.h"
|
||||
extern int dyngen_code(uint8_t *gen_code_buf,
|
||||
uint16_t *label_offsets, uint16_t *jmp_offsets,
|
||||
const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels);
|
||||
#include "op.h"
|
||||
|
Loading…
Reference in New Issue
Block a user