Convert unaligned load/store to TCG.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4759 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
ths 2008-06-20 15:12:14 +00:00
parent 9fac3a3a7e
commit c8c2227e91
5 changed files with 364 additions and 71 deletions

6
configure vendored
View File

@ -1280,28 +1280,22 @@ case "$target_cpu" in
;;
mips|mipsel)
echo "TARGET_ARCH=mips" >> $config_mak
echo "CONFIG_DYNGEN_OP=yes" >> $config_mak
echo "#define TARGET_ARCH \"mips\"" >> $config_h
echo "#define TARGET_MIPS 1" >> $config_h
echo "#define TARGET_ABI_MIPSO32 1" >> $config_h
echo "#define CONFIG_DYNGEN_OP 1" >> $config_h
;;
mipsn32|mipsn32el)
echo "TARGET_ARCH=mipsn32" >> $config_mak
echo "CONFIG_DYNGEN_OP=yes" >> $config_mak
echo "#define TARGET_ARCH \"mipsn32\"" >> $config_h
echo "#define TARGET_MIPS 1" >> $config_h
echo "#define TARGET_ABI_MIPSN32 1" >> $config_h
echo "#define CONFIG_DYNGEN_OP 1" >> $config_h
;;
mips64|mips64el)
echo "TARGET_ARCH=mips64" >> $config_mak
echo "CONFIG_DYNGEN_OP=yes" >> $config_mak
echo "#define TARGET_ARCH \"mips64\"" >> $config_h
echo "#define TARGET_MIPS 1" >> $config_h
echo "#define TARGET_MIPS64 1" >> $config_h
echo "#define TARGET_ABI_MIPSN64 1" >> $config_h
echo "#define CONFIG_DYNGEN_OP 1" >> $config_h
;;
ppc)
echo "TARGET_ARCH=ppc" >> $config_mak

View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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: