aboutsummaryrefslogtreecommitdiff
path: root/target-mips
diff options
context:
space:
mode:
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>2008-06-20 15:12:14 +0000
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>2008-06-20 15:12:14 +0000
commitc8c2227e913e5a41cc44746e22ad73e9880c06fb (patch)
treeda132b4499b58cc6e4ecc8dfe12bb801e71914d0 /target-mips
parent9fac3a3a7e7c7c6379179da8461894ad1249c87e (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.h11
-rw-r--r--target-mips/op.c26
-rw-r--r--target-mips/op_helper.c337
-rw-r--r--target-mips/translate.c55
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: