diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-05-30 20:56:52 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-05-30 20:56:52 +0000 |
commit | 932a69096921c3091ef1ce2b93cc809eb6ec8027 (patch) | |
tree | 4017655a5530eb30c16b1d31a7e77d7ef3ff0f00 | |
parent | da260249a4109b1ac82016b27973c50f0a74311a (diff) |
support of long calls for PPC (malc)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4629 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | exec-all.h | 17 | ||||
-rw-r--r-- | tcg/ppc/tcg-target.c | 94 | ||||
-rw-r--r-- | tcg/tcg.h | 5 |
3 files changed, 82 insertions, 34 deletions
diff --git a/exec-all.h b/exec-all.h index 1f5906c7c4..6cc3f70f44 100644 --- a/exec-all.h +++ b/exec-all.h @@ -187,12 +187,23 @@ extern int code_gen_max_blocks; static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) { uint32_t val, *ptr; + long disp = addr - jmp_addr; - /* patch the branch destination */ ptr = (uint32_t *)jmp_addr; val = *ptr; - val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc); - *ptr = val; + + if ((disp << 6) >> 6 != disp) { + uint16_t *p1; + + p1 = (uint16_t *) ptr; + *ptr = (val & ~0x03fffffc) | 4; + p1[3] = addr >> 16; + p1[5] = addr & 0xffff; + } else { + /* patch the branch destination */ + val = (val & ~0x03fffffc) | (disp & 0x03fffffc); + *ptr = val; + } /* flush icache */ asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory"); asm volatile ("sync" : : : "memory"); diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c index 4bbedba3c8..6d955c9499 100644 --- a/tcg/ppc/tcg-target.c +++ b/tcg/ppc/tcg-target.c @@ -24,9 +24,6 @@ static uint8_t *tb_ret_addr; -#define TCG_CT_PC14 0x100 -#define TCG_CT_PC24 0x200 - #define FAST_PATH #if TARGET_PHYS_ADDR_BITS <= 32 #define ADDEND_OFFSET 0 @@ -140,7 +137,13 @@ static const int tcg_target_callee_save_regs[] = { static uint32_t reloc_pc24_val (void *pc, tcg_target_long target) { - return (target - (tcg_target_long) pc) & 0x3fffffc; + tcg_target_long disp; + + disp = target - (tcg_target_long) pc; + if ((disp << 6) >> 6 != disp) + tcg_abort (); + + return disp & 0x3fffffc; } static void reloc_pc24 (void *pc, tcg_target_long target) @@ -151,7 +154,13 @@ static void reloc_pc24 (void *pc, tcg_target_long target) static uint16_t reloc_pc14_val (void *pc, tcg_target_long target) { - return (target - (tcg_target_long) pc) & 0xfffc; + tcg_target_long disp; + + disp = target - (tcg_target_long) pc; + if (disp != (int16_t) disp) + tcg_abort (); + + return disp & 0xfffc; } static void reloc_pc14 (void *pc, tcg_target_long target) @@ -218,12 +227,6 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); tcg_regset_reset_reg(ct->u.regs, TCG_REG_R7); break; - case 'J': /* 24 bit displacement */ - ct->ct |= TCG_CT_PC24; - break; - case 'j': /* 16 bit displacement */ - ct->ct |= TCG_CT_PC14; - break; default: return -1; } @@ -241,13 +244,6 @@ static int tcg_target_const_match(tcg_target_long val, ct = arg_ct->ct; if (ct & TCG_CT_CONST) return 1; - else if (ct & TCG_CT_PC14) { - return val == (int16_t) val; - } - else if (ct & TCG_CT_PC24) { - if (val < 0) return val > -0x800000; - return val < 0x7fffff; - } return 0; } @@ -407,6 +403,20 @@ static void tcg_out_ldst (TCGContext *s, int ret, int addr, } } +static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target) +{ + tcg_target_long disp; + + disp = target - (tcg_target_long) s->code_ptr; + if ((disp << 6) >> 6 == disp) + tcg_out32 (s, B | disp | mask); + else { + tcg_out_movi (s, TCG_TYPE_I32, 0, (tcg_target_long) target); + tcg_out32 (s, MTSPR | RS (0) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS | mask); + } +} + #if defined(CONFIG_SOFTMMU) extern void __ldb_mmu(void); extern void __ldw_mmu(void); @@ -507,8 +517,7 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) tcg_out_movi (s, TCG_TYPE_I32, 5, mem_index); #endif - tcg_out32 (s, B | reloc_pc24_val (s->code_ptr, - (tcg_target_long) qemu_ld_helpers[s_bits]) | LK); + tcg_out_b (s, LK, (tcg_target_long) qemu_ld_helpers[s_bits]); switch (opc) { case 0|4: tcg_out32 (s, EXTSB | RA (data_reg) | RS (3)); @@ -727,8 +736,7 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) ir++; tcg_out_movi (s, TCG_TYPE_I32, ir, mem_index); - tcg_out32 (s, B | reloc_pc24_val (s->code_ptr, - (tcg_target_long) qemu_st_helpers[opc]) | LK); + tcg_out_b (s, LK, (tcg_target_long) qemu_st_helpers[opc]); label2_ptr = s->code_ptr; tcg_out32 (s, B); @@ -932,6 +940,12 @@ static void tcg_out_brcond(TCGContext *s, int cond, } if (l->has_value) { + tcg_target_long disp; + + disp = (tcg_target_long) s->code_ptr - l->u.value; + if (disp != (int16_t) disp) + tcg_abort (); + tcg_out32 (s, tcg_to_bc[cond] | reloc_pc14_val (s->code_ptr, l->u.value)); } @@ -1010,14 +1024,31 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, switch (opc) { case INDEX_op_exit_tb: tcg_out_movi (s, TCG_TYPE_I32, TCG_REG_R3, args[0]); - tcg_out32 (s, B | reloc_pc24_val (s->code_ptr, (tcg_target_long) tb_ret_addr)); + tcg_out_b (s, 0, (tcg_target_long) tb_ret_addr); break; case INDEX_op_goto_tb: if (s->tb_jmp_offset) { /* direct jump method */ + uint32_t val; + uint16_t *p; + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; - tcg_out32 (s, B | 4); - } else { + /* Thanks to Andrzej Zaborowski for this */ + val = *(uint32_t *) s->code_ptr & 0x3fffffc; + + tcg_out32 (s, B | val); + + /* For branches outside of LL range + This must be in concord with tb_set_jmp_target1 */ + p = (uint16_t *) s->code_ptr; + p[0] = (ADDIS | RT (0) | RA (0)) >> 16; + p[2] = (ORI | RT (0) | RA (0)) >> 16; + s->code_ptr += 8; + + tcg_out32 (s, MTSPR | RS (0) | CTR); + tcg_out32 (s, BCCTR | BO_ALWAYS); + } + else { tcg_abort (); } s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; @@ -1027,7 +1058,7 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, TCGLabel *l = &s->labels[args[0]]; if (l->has_value) { - tcg_out32 (s, B | reloc_pc24_val (s->code_ptr, l->u.value)); + tcg_out_b (s, 0, l->u.value); } else { tcg_out32 (s, B); @@ -1037,7 +1068,7 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, break; case INDEX_op_call: if (const_args[0]) { - tcg_out32 (s, B | reloc_pc24_val (s->code_ptr, args[0]) | LK); + tcg_out_b (s, LK, args[0]); } else { tcg_out32 (s, MTSPR | RS (args[0]) | LR); @@ -1046,7 +1077,7 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, break; case INDEX_op_jmp: if (const_args[0]) { - tcg_out32 (s, B | reloc_pc24_val (s->code_ptr, args[0])); + tcg_out_b (s, 0, args[0]); } else { tcg_out32 (s, MTSPR | RS (args[0]) | CTR); @@ -1122,7 +1153,8 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, if (const_args[2]) { if (args[2]) { if (args[2] & 0xffff) { - tcg_out32 (s, ORI | RS (args[1]) | RA (args[0]) | (args[2] & 0xffff)); + tcg_out32 (s, ORI | RS (args[1]) | RA (args[0]) + | (args[2] & 0xffff)); if (args[2] >> 16) tcg_out32 (s, ORIS | RS (args[0]) | RA (args[0]) | ((args[2] >> 16) & 0xffff)); @@ -1338,8 +1370,8 @@ static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, static const TCGTargetOpDef ppc_op_defs[] = { { INDEX_op_exit_tb, { } }, { INDEX_op_goto_tb, { } }, - { INDEX_op_call, { "rJ" } }, - { INDEX_op_jmp, { "rJ" } }, + { INDEX_op_call, { "ri" } }, + { INDEX_op_jmp, { "ri" } }, { INDEX_op_br, { } }, { INDEX_op_mov_i32, { "r", "r" } }, @@ -410,4 +410,9 @@ uint64_t tcg_helper_divu_i64(uint64_t arg1, uint64_t arg2); uint64_t tcg_helper_remu_i64(uint64_t arg1, uint64_t arg2); extern uint8_t code_gen_prologue[]; +#ifdef __powerpc__ +#define tcg_qemu_tb_exec(tb_ptr) \ + ((long REGPARM __attribute__ ((longcall)) (*)(void *))code_gen_prologue)(tb_ptr) +#else #define tcg_qemu_tb_exec(tb_ptr) ((long REGPARM (*)(void *))code_gen_prologue)(tb_ptr) +#endif |