aboutsummaryrefslogtreecommitdiff
path: root/translate-i386.c
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-05-25 16:46:15 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2003-05-25 16:46:15 +0000
commitd4e8164f7e9342d692c1d6f1c848ed05f8007ece (patch)
treeca8f3b46553b2674eb5ab3297b39db75d78ba4d4 /translate-i386.c
parent08351fb37ae0abe0d0a025ad67709f1f1fd63d59 (diff)
direct chaining for PowerPC and i386
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@183 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'translate-i386.c')
-rw-r--r--translate-i386.c118
1 files changed, 68 insertions, 50 deletions
diff --git a/translate-i386.c b/translate-i386.c
index 32e188bbb7..9ef7a3b058 100644
--- a/translate-i386.c
+++ b/translate-i386.c
@@ -31,11 +31,15 @@
#define IN_OP_I386
#include "cpu-i386.h"
+#include "exec.h"
/* XXX: move that elsewhere */
static uint16_t *gen_opc_ptr;
static uint32_t *gen_opparam_ptr;
int __op_param1, __op_param2, __op_param3;
+#ifdef USE_DIRECT_JUMP
+int __op_jmp0, __op_jmp1;
+#endif
#ifdef __i386__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
@@ -67,14 +71,14 @@ static void inline flush_icache_range(unsigned long start, unsigned long stop)
stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
- asm ("dcbst 0,%0;" : : "r"(p) : "memory");
+ asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
}
- asm ("sync");
+ asm volatile ("sync" : : : "memory");
for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
- asm ("icbi 0,%0; sync;" : : "r"(p) : "memory");
+ asm volatile ("icbi 0,%0" : : "r"(p) : "memory");
}
- asm ("sync");
- asm ("isync");
+ asm volatile ("sync" : : : "memory");
+ asm volatile ("isync" : : : "memory");
}
#endif
@@ -129,6 +133,7 @@ typedef struct DisasContext {
int cpl;
int iopl;
int tf; /* TF cpu flag */
+ TranslationBlock *tb;
} DisasContext;
/* i386 arith/logic operations */
@@ -192,6 +197,7 @@ enum {
typedef void (GenOpFunc)(void);
typedef void (GenOpFunc1)(long);
typedef void (GenOpFunc2)(long, long);
+typedef void (GenOpFunc3)(long, long, long);
static GenOpFunc *gen_op_mov_reg_T0[3][8] = {
[OT_BYTE] = {
@@ -699,18 +705,7 @@ enum {
JCC_LE,
};
-static GenOpFunc2 *gen_jcc_slow[8] = {
- gen_op_jo_cc,
- gen_op_jb_cc,
- gen_op_jz_cc,
- gen_op_jbe_cc,
- gen_op_js_cc,
- gen_op_jp_cc,
- gen_op_jl_cc,
- gen_op_jle_cc,
-};
-
-static GenOpFunc2 *gen_jcc_sub[3][8] = {
+static GenOpFunc3 *gen_jcc_sub[3][8] = {
[OT_BYTE] = {
NULL,
gen_op_jb_subb,
@@ -1090,8 +1085,9 @@ static inline uint32_t insn_get(DisasContext *s, int ot)
static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip)
{
+ TranslationBlock *tb;
int inv, jcc_op;
- GenOpFunc2 *func;
+ GenOpFunc3 *func;
inv = b & 1;
jcc_op = (b >> 1) & 7;
@@ -1101,8 +1097,6 @@ static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip)
case CC_OP_SUBW:
case CC_OP_SUBL:
func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op];
- if (!func)
- goto slow_jcc;
break;
/* some jumps are easy to compute */
@@ -1138,21 +1132,30 @@ static inline void gen_jcc(DisasContext *s, int b, int val, int next_eip)
func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 3][jcc_op];
break;
default:
- goto slow_jcc;
+ func = NULL;
+ break;
}
break;
default:
- slow_jcc:
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- func = gen_jcc_slow[jcc_op];
+ func = NULL;
break;
}
+
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+
+ if (!func) {
+ gen_setcc_slow[jcc_op]();
+ func = gen_op_jcc;
+ }
+
+ tb = s->tb;
if (!inv) {
- func(val, next_eip);
+ func((long)tb, val, next_eip);
} else {
- func(next_eip, val);
+ func((long)tb, next_eip, val);
}
+ s->is_jmp = 3;
}
static void gen_setcc(DisasContext *s, int b)
@@ -1372,6 +1375,18 @@ static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip)
s->is_jmp = 1;
}
+/* generate a jump to eip. No segment change must happen before as a
+ direct call to the next block may occur */
+static void gen_jmp(DisasContext *s, unsigned int eip)
+{
+ TranslationBlock *tb = s->tb;
+
+ if (s->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(s->cc_op);
+ gen_op_jmp_tb_next((long)tb, eip);
+ s->is_jmp = 3;
+}
+
/* return the next pc address. Return -1 if no insn found. *is_jmp_ptr
is set to true if the instruction sets the PC (last instruction of
a basic block) */
@@ -2964,8 +2979,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
val &= 0xffff;
gen_op_movl_T0_im(next_eip);
gen_push_T0(s);
- gen_op_jmp_im(val);
- s->is_jmp = 1;
+ gen_jmp(s, val);
}
break;
case 0x9a: /* lcall im */
@@ -2996,8 +3010,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
val += s->pc - s->cs_base;
if (s->dflag == 0)
val = val & 0xffff;
- gen_op_jmp_im(val);
- s->is_jmp = 1;
+ gen_jmp(s, val);
break;
case 0xea: /* ljmp im */
{
@@ -3019,8 +3032,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
val += s->pc - s->cs_base;
if (s->dflag == 0)
val = val & 0xffff;
- gen_op_jmp_im(val);
- s->is_jmp = 1;
+ gen_jmp(s, val);
break;
case 0x70 ... 0x7f: /* jcc Jb */
val = (int8_t)insn_get(s, OT_BYTE);
@@ -3037,7 +3049,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
if (s->dflag == 0)
val &= 0xffff;
gen_jcc(s, b, val, next_eip);
- s->is_jmp = 1;
break;
case 0x190 ... 0x19f: /* setcc Gv */
@@ -3393,15 +3404,6 @@ static uint16_t opc_read_flags[NB_OPS] = {
[INDEX_op_into] = CC_O,
- [INDEX_op_jo_cc] = CC_O,
- [INDEX_op_jb_cc] = CC_C,
- [INDEX_op_jz_cc] = CC_Z,
- [INDEX_op_jbe_cc] = CC_Z | CC_C,
- [INDEX_op_js_cc] = CC_S,
- [INDEX_op_jp_cc] = CC_P,
- [INDEX_op_jl_cc] = CC_O | CC_S,
- [INDEX_op_jle_cc] = CC_O | CC_S | CC_Z,
-
[INDEX_op_jb_subb] = CC_C,
[INDEX_op_jb_subw] = CC_C,
[INDEX_op_jb_subl] = CC_C,
@@ -3730,7 +3732,7 @@ static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
int *gen_code_size_ptr,
uint8_t *pc_start, uint8_t *cs_base, int flags,
- int *code_size_ptr)
+ int *code_size_ptr, TranslationBlock *tb)
{
DisasContext dc1, *dc = &dc1;
uint8_t *pc_ptr;
@@ -3750,6 +3752,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
dc->tf = (flags >> GEN_FLAG_TF_SHIFT) & 1;
dc->cc_op = CC_OP_DYNAMIC;
dc->cs_base = cs_base;
+ dc->tb = tb;
gen_opc_ptr = gen_opc_buf;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
@@ -3776,15 +3779,21 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
(pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32));
/* we must store the eflags state if it is not already done */
- if (dc->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(dc->cc_op);
- if (dc->is_jmp != 1) {
- /* we add an additionnal jmp to update the simulated PC */
- gen_op_jmp_im(ret - (unsigned long)dc->cs_base);
+ if (dc->is_jmp != 3) {
+ if (dc->cc_op != CC_OP_DYNAMIC)
+ gen_op_set_cc_op(dc->cc_op);
+ if (dc->is_jmp != 1) {
+ /* we add an additionnal jmp to update the simulated PC */
+ gen_op_jmp_im(ret - (unsigned long)dc->cs_base);
+ }
}
if (dc->tf) {
gen_op_raise_exception(EXCP01_SSTP);
}
+ if (dc->is_jmp != 3) {
+ /* indicate that the hash table must be used to find the next TB */
+ gen_op_movl_T0_0();
+ }
*gen_opc_ptr = INDEX_op_end;
@@ -3814,8 +3823,17 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
#endif
/* generate machine code */
- gen_code_size = dyngen_code(gen_code_buf, gen_opc_buf, gen_opparam_buf);
+ tb->tb_next_offset[0] = 0xffff;
+ tb->tb_next_offset[1] = 0xffff;
+ gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
+#ifdef USE_DIRECT_JUMP
+ tb->tb_jmp_offset,
+#else
+ NULL,
+#endif
+ gen_opc_buf, gen_opparam_buf);
flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size));
+
*gen_code_size_ptr = gen_code_size;
*code_size_ptr = pc_ptr - pc_start;
#ifdef DEBUG_DISAS