Commit c8c2227e authored by Thiemo Seufer's avatar Thiemo Seufer
Browse files

Convert unaligned load/store to TCG.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4759 c046a42c-6fe2-441c-8c8c-71466251a162
parent 9fac3a3a
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -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
+11 −0
Original line number Diff line number Diff line
@@ -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
+0 −26
Original line number Diff line number Diff line
@@ -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
+337 −0
Original line number Diff line number Diff line
@@ -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)
{
+16 −39
Original line number Diff line number Diff line
@@ -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: