diff options
author | ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-06-20 15:12:14 +0000 |
---|---|---|
committer | ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-06-20 15:12:14 +0000 |
commit | c8c2227e913e5a41cc44746e22ad73e9880c06fb (patch) | |
tree | da132b4499b58cc6e4ecc8dfe12bb801e71914d0 /target-mips | |
parent | 9fac3a3a7e7c7c6379179da8461894ad1249c87e (diff) |
Convert unaligned load/store to TCG.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4759 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-mips')
-rw-r--r-- | target-mips/helper.h | 11 | ||||
-rw-r--r-- | target-mips/op.c | 26 | ||||
-rw-r--r-- | target-mips/op_helper.c | 337 | ||||
-rw-r--r-- | target-mips/translate.c | 55 |
4 files changed, 364 insertions, 65 deletions
diff --git a/target-mips/helper.h b/target-mips/helper.h index 617e6d4242..1638d29b33 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -6,6 +6,17 @@ DEF_HELPER(void, do_raise_exception_err, (int excp, int err)) DEF_HELPER(void, do_raise_exception, (int excp)) DEF_HELPER(void, do_interrupt_restart, (void)) +#ifdef TARGET_MIPS64 +DEF_HELPER(void, do_ldl, (int mem_idx)) +DEF_HELPER(void, do_ldr, (int mem_idx)) +DEF_HELPER(void, do_sdl, (int mem_idx)) +DEF_HELPER(void, do_sdr, (int mem_idx)) +#endif +DEF_HELPER(void, do_lwl, (int mem_idx)) +DEF_HELPER(void, do_lwr, (int mem_idx)) +DEF_HELPER(void, do_swl, (int mem_idx)) +DEF_HELPER(void, do_swr, (int mem_idx)) + DEF_HELPER(void, do_clo, (void)) DEF_HELPER(void, do_clz, (void)) #ifdef TARGET_MIPS64 diff --git a/target-mips/op.c b/target-mips/op.c index d617a076d5..cbe4f413b6 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -19,29 +19,3 @@ * 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 "config.h" -#include "exec.h" -#include "host-utils.h" - -#ifndef CALL_FROM_TB0 -#define CALL_FROM_TB0(func) func() -#endif - -/* Load and store */ -#define MEMSUFFIX _raw -#include "op_mem.c" -#undef MEMSUFFIX -#if !defined(CONFIG_USER_ONLY) -#define MEMSUFFIX _user -#include "op_mem.c" -#undef MEMSUFFIX - -#define MEMSUFFIX _super -#include "op_mem.c" -#undef MEMSUFFIX - -#define MEMSUFFIX _kernel -#include "op_mem.c" -#undef MEMSUFFIX -#endif diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 16d3023a45..602116a8b3 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -308,6 +308,343 @@ void do_dmultu (void) } #endif +#ifdef TARGET_WORDS_BIGENDIAN +#define GET_LMASK(v) ((v) & 3) +#define GET_OFFSET(addr, offset) (addr + (offset)) +#else +#define GET_LMASK(v) (((v) & 3) ^ 3) +#define GET_OFFSET(addr, offset) (addr - (offset)) +#endif + +void do_lwl(int mem_idx) +{ + target_ulong tmp; + +#ifdef CONFIG_USER_ONLY +#define ldfun ldub_raw +#else + int (*ldfun)(target_ulong); + + switch (mem_idx) + { + case 0: ldfun = ldub_kernel; break; + case 1: ldfun = ldub_super; break; + default: + case 2: ldfun = ldub_user; break; + } +#endif + tmp = ldfun(T0); + T1 = (T1 & 0x00FFFFFF) | (tmp << 24); + + if (GET_LMASK(T0) <= 2) { + tmp = ldfun(GET_OFFSET(T0, 1)); + T1 = (T1 & 0xFF00FFFF) | (tmp << 16); + } + + if (GET_LMASK(T0) <= 1) { + tmp = ldfun(GET_OFFSET(T0, 2)); + T1 = (T1 & 0xFFFF00FF) | (tmp << 8); + } + + if (GET_LMASK(T0) == 0) { + tmp = ldfun(GET_OFFSET(T0, 3)); + T1 = (T1 & 0xFFFFFF00) | tmp; + } + T1 = (int32_t)T1; +} + +void do_lwr(int mem_idx) +{ + target_ulong tmp; + +#ifdef CONFIG_USER_ONLY +#define ldfun ldub_raw +#else + int (*ldfun)(target_ulong); + + switch (mem_idx) + { + case 0: ldfun = ldub_kernel; break; + case 1: ldfun = ldub_super; break; + default: + case 2: ldfun = ldub_user; break; + } +#endif + tmp = ldfun(T0); + T1 = (T1 & 0xFFFFFF00) | tmp; + + if (GET_LMASK(T0) >= 1) { + tmp = ldfun(GET_OFFSET(T0, -1)); + T1 = (T1 & 0xFFFF00FF) | (tmp << 8); + } + + if (GET_LMASK(T0) >= 2) { + tmp = ldfun(GET_OFFSET(T0, -2)); + T1 = (T1 & 0xFF00FFFF) | (tmp << 16); + } + + if (GET_LMASK(T0) == 3) { + tmp = ldfun(GET_OFFSET(T0, -3)); + T1 = (T1 & 0x00FFFFFF) | (tmp << 24); + } + T1 = (int32_t)T1; +} + +void do_swl(int mem_idx) +{ +#ifdef CONFIG_USER_ONLY +#define stfun stb_raw +#else + void (*stfun)(target_ulong, int); + + switch (mem_idx) + { + case 0: stfun = stb_kernel; break; + case 1: stfun = stb_super; break; + default: + case 2: stfun = stb_user; break; + } +#endif + stfun(T0, (uint8_t)(T1 >> 24)); + + if (GET_LMASK(T0) <= 2) + stfun(GET_OFFSET(T0, 1), (uint8_t)(T1 >> 16)); + + if (GET_LMASK(T0) <= 1) + stfun(GET_OFFSET(T0, 2), (uint8_t)(T1 >> 8)); + + if (GET_LMASK(T0) == 0) + stfun(GET_OFFSET(T0, 3), (uint8_t)T1); +} + +void do_swr(int mem_idx) +{ +#ifdef CONFIG_USER_ONLY +#define stfun stb_raw +#else + void (*stfun)(target_ulong, int); + + switch (mem_idx) + { + case 0: stfun = stb_kernel; break; + case 1: stfun = stb_super; break; + default: + case 2: stfun = stb_user; break; + } +#endif + stfun(T0, (uint8_t)T1); + + if (GET_LMASK(T0) >= 1) + stfun(GET_OFFSET(T0, -1), (uint8_t)(T1 >> 8)); + + if (GET_LMASK(T0) >= 2) + stfun(GET_OFFSET(T0, -2), (uint8_t)(T1 >> 16)); + + if (GET_LMASK(T0) == 3) + stfun(GET_OFFSET(T0, -3), (uint8_t)(T1 >> 24)); +} + +#if defined(TARGET_MIPS64) +/* "half" load and stores. We must do the memory access inline, + or fault handling won't work. */ + +#ifdef TARGET_WORDS_BIGENDIAN +#define GET_LMASK64(v) ((v) & 7) +#else +#define GET_LMASK64(v) (((v) & 7) ^ 7) +#endif + +void do_ldl(int mem_idx) +{ + uint64_t tmp; + +#ifdef CONFIG_USER_ONLY +#define ldfun ldub_raw +#else + target_ulong (*ldfun)(target_ulong); + + switch (mem_idx) + { + case 0: ldfun = ldub_kernel; break; + case 1: ldfun = ldub_super; break; + default: + case 2: ldfun = ldub_user; break; + } +#endif + tmp = ldfun(T0); + T1 = (T1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); + + if (GET_LMASK64(T0) <= 6) { + tmp = ldfun(GET_OFFSET(T0, 1)); + T1 = (T1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48); + } + + if (GET_LMASK64(T0) <= 5) { + tmp = ldfun(GET_OFFSET(T0, 2)); + T1 = (T1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40); + } + + if (GET_LMASK64(T0) <= 4) { + tmp = ldfun(GET_OFFSET(T0, 3)); + T1 = (T1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32); + } + + if (GET_LMASK64(T0) <= 3) { + tmp = ldfun(GET_OFFSET(T0, 4)); + T1 = (T1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24); + } + + if (GET_LMASK64(T0) <= 2) { + tmp = ldfun(GET_OFFSET(T0, 5)); + T1 = (T1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16); + } + + if (GET_LMASK64(T0) <= 1) { + tmp = ldfun(GET_OFFSET(T0, 6)); + T1 = (T1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8); + } + + if (GET_LMASK64(T0) == 0) { + tmp = ldfun(GET_OFFSET(T0, 7)); + T1 = (T1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; + } +} + +void do_ldr(int mem_idx) +{ + uint64_t tmp; + +#ifdef CONFIG_USER_ONLY +#define ldfun ldub_raw +#else + target_ulong (*ldfun)(target_ulong); + + switch (mem_idx) + { + case 0: ldfun = ldub_kernel; break; + case 1: ldfun = ldub_super; break; + default: + case 2: ldfun = ldub_user; break; + } +#endif + tmp = ldfun(T0); + T1 = (T1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; + + if (GET_LMASK64(T0) >= 1) { + tmp = ldfun(GET_OFFSET(T0, -1)); + T1 = (T1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8); + } + + if (GET_LMASK64(T0) >= 2) { + tmp = ldfun(GET_OFFSET(T0, -2)); + T1 = (T1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16); + } + + if (GET_LMASK64(T0) >= 3) { + tmp = ldfun(GET_OFFSET(T0, -3)); + T1 = (T1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24); + } + + if (GET_LMASK64(T0) >= 4) { + tmp = ldfun(GET_OFFSET(T0, -4)); + T1 = (T1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32); + } + + if (GET_LMASK64(T0) >= 5) { + tmp = ldfun(GET_OFFSET(T0, -5)); + T1 = (T1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40); + } + + if (GET_LMASK64(T0) >= 6) { + tmp = ldfun(GET_OFFSET(T0, -6)); + T1 = (T1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48); + } + + if (GET_LMASK64(T0) == 7) { + tmp = ldfun(GET_OFFSET(T0, -7)); + T1 = (T1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); + } +} + +void do_sdl(int mem_idx) +{ +#ifdef CONFIG_USER_ONLY +#define stfun stb_raw +#else + void (*stfun)(target_ulong, int); + + switch (mem_idx) + { + case 0: stfun = stb_kernel; break; + case 1: stfun = stb_super; break; + default: + case 2: stfun = stb_user; break; + } +#endif + stfun(T0, (uint8_t)(T1 >> 56)); + + if (GET_LMASK64(T0) <= 6) + stfun(GET_OFFSET(T0, 1), (uint8_t)(T1 >> 48)); + + if (GET_LMASK64(T0) <= 5) + stfun(GET_OFFSET(T0, 2), (uint8_t)(T1 >> 40)); + + if (GET_LMASK64(T0) <= 4) + stfun(GET_OFFSET(T0, 3), (uint8_t)(T1 >> 32)); + + if (GET_LMASK64(T0) <= 3) + stfun(GET_OFFSET(T0, 4), (uint8_t)(T1 >> 24)); + + if (GET_LMASK64(T0) <= 2) + stfun(GET_OFFSET(T0, 5), (uint8_t)(T1 >> 16)); + + if (GET_LMASK64(T0) <= 1) + stfun(GET_OFFSET(T0, 6), (uint8_t)(T1 >> 8)); + + if (GET_LMASK64(T0) <= 0) + stfun(GET_OFFSET(T0, 7), (uint8_t)T1); +} + +void do_sdr(int mem_idx) +{ +#ifdef CONFIG_USER_ONLY +#define stfun stb_raw +#else + void (*stfun)(target_ulong, int); + + switch (mem_idx) + { + case 0: stfun = stb_kernel; break; + case 1: stfun = stb_super; break; + default: + case 2: stfun = stb_user; break; + } +#endif + stfun(T0, (uint8_t)T1); + + if (GET_LMASK64(T0) >= 1) + stfun(GET_OFFSET(T0, -1), (uint8_t)(T1 >> 8)); + + if (GET_LMASK64(T0) >= 2) + stfun(GET_OFFSET(T0, -2), (uint8_t)(T1 >> 16)); + + if (GET_LMASK64(T0) >= 3) + stfun(GET_OFFSET(T0, -3), (uint8_t)(T1 >> 24)); + + if (GET_LMASK64(T0) >= 4) + stfun(GET_OFFSET(T0, -4), (uint8_t)(T1 >> 32)); + + if (GET_LMASK64(T0) >= 5) + stfun(GET_OFFSET(T0, -5), (uint8_t)(T1 >> 40)); + + if (GET_LMASK64(T0) >= 6) + stfun(GET_OFFSET(T0, -6), (uint8_t)(T1 >> 48)); + + if (GET_LMASK64(T0) == 7) + stfun(GET_OFFSET(T0, -7), (uint8_t)(T1 >> 56)); +} +#endif /* TARGET_MIPS64 */ + #ifdef CONFIG_USER_ONLY void do_mfc0_random (void) { diff --git a/target-mips/translate.c b/target-mips/translate.c index d441f2bdff..9fdf836a09 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -945,37 +945,6 @@ static always_inline void check_mips_64(DisasContext *ctx) } /* load/store instructions. */ -#if defined(CONFIG_USER_ONLY) -#define op_ldst(name) gen_op_##name##_raw() -#define OP_LD_TABLE(width) -#define OP_ST_TABLE(width) -#else -#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() -#define OP_LD_TABLE(width) \ -static GenOpFunc *gen_op_l##width[] = { \ - &gen_op_l##width##_kernel, \ - &gen_op_l##width##_super, \ - &gen_op_l##width##_user, \ -} -#define OP_ST_TABLE(width) \ -static GenOpFunc *gen_op_s##width[] = { \ - &gen_op_s##width##_kernel, \ - &gen_op_s##width##_super, \ - &gen_op_s##width##_user, \ -} -#endif - -#if defined(TARGET_MIPS64) -OP_LD_TABLE(dl); -OP_LD_TABLE(dr); -OP_ST_TABLE(dl); -OP_ST_TABLE(dr); -#endif -OP_LD_TABLE(wl); -OP_LD_TABLE(wr); -OP_ST_TABLE(wl); -OP_ST_TABLE(wr); - #define OP_LD(insn,fname) \ void inline op_ldst_##insn(DisasContext *ctx) \ { \ @@ -1094,25 +1063,29 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, opn = "scd"; break; case OPC_LDL: + save_cpu_state(ctx, 1); gen_load_gpr(cpu_T[1], rt); - op_ldst(ldl); + tcg_gen_helper_0_1i(do_ldl, ctx->mem_idx); gen_store_gpr(cpu_T[1], rt); opn = "ldl"; break; case OPC_SDL: + save_cpu_state(ctx, 1); gen_load_gpr(cpu_T[1], rt); - op_ldst(sdl); + tcg_gen_helper_0_1i(do_sdl, ctx->mem_idx); opn = "sdl"; break; case OPC_LDR: + save_cpu_state(ctx, 1); gen_load_gpr(cpu_T[1], rt); - op_ldst(ldr); + tcg_gen_helper_0_1i(do_ldr, ctx->mem_idx); gen_store_gpr(cpu_T[1], rt); opn = "ldr"; break; case OPC_SDR: + save_cpu_state(ctx, 1); gen_load_gpr(cpu_T[1], rt); - op_ldst(sdr); + tcg_gen_helper_0_1i(do_sdr, ctx->mem_idx); opn = "sdr"; break; #endif @@ -1157,25 +1130,29 @@ static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt, opn = "lbu"; break; case OPC_LWL: + save_cpu_state(ctx, 1); gen_load_gpr(cpu_T[1], rt); - op_ldst(lwl); + tcg_gen_helper_0_1i(do_lwl, ctx->mem_idx); gen_store_gpr(cpu_T[1], rt); opn = "lwl"; break; case OPC_SWL: + save_cpu_state(ctx, 1); gen_load_gpr(cpu_T[1], rt); - op_ldst(swl); + tcg_gen_helper_0_1i(do_swl, ctx->mem_idx); opn = "swr"; break; case OPC_LWR: + save_cpu_state(ctx, 1); gen_load_gpr(cpu_T[1], rt); - op_ldst(lwr); + tcg_gen_helper_0_1i(do_lwr, ctx->mem_idx); gen_store_gpr(cpu_T[1], rt); opn = "lwr"; break; case OPC_SWR: + save_cpu_state(ctx, 1); gen_load_gpr(cpu_T[1], rt); - op_ldst(swr); + tcg_gen_helper_0_1i(do_swr, ctx->mem_idx); opn = "swr"; break; case OPC_LL: |