diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2004-02-16 20:30:05 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2004-02-16 20:30:05 +0000 |
commit | 72cbca10e184637ec0e813ead71975b7446cc695 (patch) | |
tree | 87196dee1ac9743831ba56469d3db52dc4c0bb63 /target-sparc | |
parent | 34f715e754adad52939d7b187fec655ddf3e0ba8 (diff) | |
download | hqemu-72cbca10e184637ec0e813ead71975b7446cc695.zip hqemu-72cbca10e184637ec0e813ead71975b7446cc695.tar.gz |
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.c | 33 | ||||
-rw-r--r-- | target-sparc/translate.c | 112 |
2 files changed, 97 insertions, 48 deletions
diff --git a/target-sparc/op.c b/target-sparc/op.c index e466e09..1ce3f95 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 f9c28d0..321b4eb 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); |