aboutsummaryrefslogtreecommitdiff
path: root/target-sparc
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2004-02-16 20:30:05 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2004-02-16 20:30:05 +0000
commit72cbca10e184637ec0e813ead71975b7446cc695 (patch)
tree87196dee1ac9743831ba56469d3db52dc4c0bb63 /target-sparc
parent34f715e754adad52939d7b187fec655ddf3e0ba8 (diff)
direct chaining support for SPARC
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@607 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-sparc')
-rw-r--r--target-sparc/op.c33
-rw-r--r--target-sparc/translate.c112
2 files changed, 97 insertions, 48 deletions
diff --git a/target-sparc/op.c b/target-sparc/op.c
index e466e09f81..1ce3f95094 100644
--- a/target-sparc/op.c
+++ b/target-sparc/op.c
@@ -643,24 +643,43 @@ void OPPROTO op_next_insn(void)
env->npc = env->npc + 4;
}
-void OPPROTO op_generic_branch(void)
+void OPPROTO op_branch(void)
+{
+ env->npc = PARAM3; /* XXX: optimize */
+ JUMP_TB(op_branch, PARAM1, 0, PARAM2);
+}
+
+void OPPROTO op_branch2(void)
{
if (T2) {
- env->npc = PARAM1;
+ env->npc = PARAM2 + 4;
+ JUMP_TB(op_branch2, PARAM1, 0, PARAM2);
} else {
- env->npc = PARAM2;
+ env->npc = PARAM3 + 4;
+ JUMP_TB(op_branch2, PARAM1, 1, PARAM3);
+ }
+ FORCE_RET();
+}
+
+void OPPROTO op_branch_a(void)
+{
+ if (T2) {
+ env->npc = PARAM2; /* XXX: optimize */
+ JUMP_TB(op_generic_branch_a, PARAM1, 0, PARAM3);
+ } else {
+ env->npc = PARAM3 + 8; /* XXX: optimize */
+ JUMP_TB(op_generic_branch_a, PARAM1, 1, PARAM3 + 4);
}
FORCE_RET();
}
-void OPPROTO op_generic_branch_a(void)
+void OPPROTO op_generic_branch(void)
{
if (T2) {
- env->pc = PARAM2;
env->npc = PARAM1;
} else {
- env->pc = PARAM2 + 4;
- env->npc = PARAM2 + 8;
+ env->npc = PARAM2;
}
FORCE_RET();
}
+
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index f9c28d080a..321b4eba4d 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -42,9 +42,14 @@
#define DEBUG_DISAS
+#define DYNAMIC_PC 1 /* dynamic pc value */
+#define JUMP_PC 2 /* dynamic pc value which takes only two values
+ according to jump_pc[T2] */
+
typedef struct DisasContext {
- uint8_t *pc; /* NULL means dynamic value */
- uint8_t *npc; /* NULL means dynamic value */
+ target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */
+ target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */
+ target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */
int is_br;
struct TranslationBlock *tb;
} DisasContext;
@@ -306,6 +311,31 @@ static inline void gen_movl_T1_reg(int reg)
gen_movl_TN_reg(reg, 1);
}
+/* call this function before using T2 as it may have been set for a jump */
+static inline void flush_T2(DisasContext * dc)
+{
+ if (dc->npc == JUMP_PC) {
+ gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]);
+ dc->npc = DYNAMIC_PC;
+ }
+}
+
+static inline void save_npc(DisasContext * dc)
+{
+ if (dc->npc == JUMP_PC) {
+ gen_op_generic_branch(dc->jump_pc[0], dc->jump_pc[1]);
+ dc->npc = DYNAMIC_PC;
+ } else if (dc->npc != DYNAMIC_PC) {
+ gen_op_movl_npc_im(dc->npc);
+ }
+}
+
+static inline void save_state(DisasContext * dc)
+{
+ gen_op_jmp_im((uint32_t)dc->pc);
+ save_npc(dc);
+}
+
static void gen_cond(int cond)
{
switch (cond) {
@@ -378,25 +408,23 @@ static void do_branch(DisasContext * dc, uint32_t target, uint32_t insn)
} else if (cond == 0x8) {
/* unconditional taken */
if (a) {
- dc->pc = (uint8_t *) target;
+ dc->pc = target;
dc->npc = dc->pc + 4;
} else {
dc->pc = dc->npc;
- dc->npc = (uint8_t *) target;
+ dc->npc = target;
}
} else {
+ flush_T2(dc);
gen_cond(cond);
if (a) {
- gen_op_generic_branch_a((uint32_t) target,
- (uint32_t) (dc->npc));
+ gen_op_branch_a((long)dc->tb, target, dc->npc);
dc->is_br = 1;
- dc->pc = NULL;
- dc->npc = NULL;
} else {
dc->pc = dc->npc;
- gen_op_generic_branch((uint32_t) target,
- (uint32_t) (dc->npc + 4));
- dc->npc = NULL;
+ dc->jump_pc[0] = target;
+ dc->jump_pc[1] = dc->npc + 4;
+ dc->npc = JUMP_PC;
}
}
}
@@ -409,18 +437,11 @@ static int sign_extend(int x, int len)
return (x << len) >> len;
}
-static inline void save_state(DisasContext * dc)
-{
- gen_op_jmp_im((uint32_t)dc->pc);
- if (dc->npc != NULL)
- gen_op_movl_npc_im((long) dc->npc);
-}
-
static void disas_sparc_insn(DisasContext * dc)
{
unsigned int insn, opc, rs1, rs2, rd;
- insn = ldl_code(dc->pc);
+ insn = ldl_code((uint8_t *)dc->pc);
opc = GET_FIELD(insn, 0, 1);
rd = GET_FIELD(insn, 2, 6);
@@ -458,9 +479,9 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_movl_T0_im((long) (dc->pc));
gen_movl_T0_reg(15);
- target = (long) dc->pc + target;
+ target = dc->pc + target;
dc->pc = dc->npc;
- dc->npc = (uint8_t *) target;
+ dc->npc = target;
}
goto jmp_insn;
case 2: /* FPU & Logical Operations */
@@ -625,7 +646,7 @@ static void disas_sparc_insn(DisasContext * dc)
gen_movl_T0_reg(rd);
}
dc->pc = dc->npc;
- dc->npc = NULL;
+ dc->npc = DYNAMIC_PC;
}
goto jmp_insn;
case 0x3b: /* flush */
@@ -705,6 +726,7 @@ static void disas_sparc_insn(DisasContext * dc)
gen_op_sth();
break;
case 0x7:
+ flush_T2(dc);
gen_movl_reg_T2(rd + 1);
gen_op_std();
break;
@@ -713,19 +735,21 @@ static void disas_sparc_insn(DisasContext * dc)
}
}
/* default case for non jump instructions */
- if (dc->npc != NULL) {
+ if (dc->npc == DYNAMIC_PC) {
+ dc->pc = DYNAMIC_PC;
+ gen_op_next_insn();
+ } else if (dc->npc == JUMP_PC) {
+ /* we can do a static jump */
+ gen_op_branch2((long)dc->tb, dc->jump_pc[0], dc->jump_pc[1]);
+ dc->is_br = 1;
+ } else {
dc->pc = dc->npc;
dc->npc = dc->npc + 4;
- } else {
- dc->pc = NULL;
- gen_op_next_insn();
}
jmp_insn:;
return;
illegal_insn:
- gen_op_jmp_im((uint32_t)dc->pc);
- if (dc->npc != NULL)
- gen_op_movl_npc_im((long) dc->npc);
+ save_state(dc);
gen_op_exception(TT_ILL_INSN);
dc->is_br = 1;
}
@@ -733,7 +757,7 @@ static void disas_sparc_insn(DisasContext * dc)
static inline int gen_intermediate_code_internal(TranslationBlock * tb,
int spc)
{
- uint8_t *pc_start, *last_pc;
+ target_ulong pc_start, last_pc;
uint16_t *gen_opc_end;
DisasContext dc1, *dc = &dc1;
@@ -743,9 +767,9 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
exit(0);
}
dc->tb = tb;
- pc_start = (uint8_t *) tb->pc;
+ pc_start = tb->pc;
dc->pc = pc_start;
- dc->npc = (uint8_t *) tb->cs_base;
+ dc->npc = (target_ulong) tb->cs_base;
gen_opc_ptr = gen_opc_buf;
gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
@@ -761,19 +785,25 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb,
break;
} while ((gen_opc_ptr < gen_opc_end) &&
(dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
- if (dc->pc != NULL)
- gen_op_jmp_im((long) dc->pc);
- if (dc->npc != NULL)
- gen_op_movl_npc_im((long) dc->npc);
- gen_op_movl_T0_0();
- gen_op_exit_tb();
-
+ if (!dc->is_br) {
+ if (dc->pc != DYNAMIC_PC &&
+ (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) {
+ /* static PC and NPC: we can use direct chaining */
+ gen_op_branch((long)tb, dc->pc, dc->npc);
+ } else {
+ if (dc->pc != DYNAMIC_PC)
+ gen_op_jmp_im(dc->pc);
+ save_npc(dc);
+ gen_op_movl_T0_0();
+ gen_op_exit_tb();
+ }
+ }
*gen_opc_ptr = INDEX_op_end;
#ifdef DEBUG_DISAS
if (loglevel) {
fprintf(logfile, "--------------\n");
- fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
- disas(logfile, pc_start, last_pc + 4 - pc_start, 0, 0);
+ fprintf(logfile, "IN: %s\n", lookup_symbol((uint8_t *)pc_start));
+ disas(logfile, (uint8_t *)pc_start, last_pc + 4 - pc_start, 0, 0);
fprintf(logfile, "\n");
fprintf(logfile, "OP:\n");
dump_ops(gen_opc_buf, gen_opparam_buf);