Index: gdbstub.c ================================================================================ --- gdbstub.c +++ gdbstub.c @@ -558,7 +558,9 @@ for (i = 0; i < 8; i++) { u.d = env->fregs[i]; *(uint32_t *)ptr = tswap32(u.l.upper); + ptr += 4; *(uint32_t *)ptr = tswap32(u.l.lower); + ptr += 8; } /* FP control regs (not implemented). */ memset (ptr, 0, 3 * 4); @@ -592,7 +594,9 @@ ColdFire has 8-bit double precision registers. */ for (i = 0; i < 8; i++) { u.l.upper = tswap32(*(uint32_t *)ptr); + ptr += 4; u.l.lower = tswap32(*(uint32_t *)ptr); + ptr += 8; env->fregs[i] = u.d; } /* FP control regs (not implemented). */ --- target-m68k/cpu.h +++ target-m68k/cpu.h @@ -89,6 +89,9 @@ uint32_t div1; uint32_t div2; + /* Upper 32 bits of a 64bit operand for quad MUL/DIV. */ + uint32_t quadh; + /* MMU status. */ struct { uint32_t ar; @@ -135,14 +138,26 @@ CC_OP_DYNAMIC, /* Use env->cc_op */ CC_OP_FLAGS, /* CC_DEST = CVZN, CC_SRC = unused */ CC_OP_LOGIC, /* CC_DEST = result, CC_SRC = unused */ + CC_OP_ADDB, /* CC_DEST = result, CC_SRC = source */ + CC_OP_ADDW, /* CC_DEST = result, CC_SRC = source */ CC_OP_ADD, /* CC_DEST = result, CC_SRC = source */ + CC_OP_SUBB, /* CC_DEST = result, CC_SRC = source */ + CC_OP_SUBW, /* CC_DEST = result, CC_SRC = source */ CC_OP_SUB, /* CC_DEST = result, CC_SRC = source */ - CC_OP_CMPB, /* CC_DEST = result, CC_SRC = source */ - CC_OP_CMPW, /* CC_DEST = result, CC_SRC = source */ + CC_OP_ADDXB, /* CC_DEST = result, CC_SRC = source */ + CC_OP_ADDXW, /* CC_DEST = result, CC_SRC = source */ CC_OP_ADDX, /* CC_DEST = result, CC_SRC = source */ + CC_OP_SUBXB, /* CC_DEST = result, CC_SRC = source */ + CC_OP_SUBXW, /* CC_DEST = result, CC_SRC = source */ CC_OP_SUBX, /* CC_DEST = result, CC_SRC = source */ + CC_OP_SHLB, /* CC_DEST = source, CC_SRC = shift */ + CC_OP_SHLW, /* CC_DEST = source, CC_SRC = shift */ CC_OP_SHL, /* CC_DEST = source, CC_SRC = shift */ + CC_OP_SHRB, /* CC_DEST = source, CC_SRC = shift */ + CC_OP_SHRW, /* CC_DEST = source, CC_SRC = shift */ CC_OP_SHR, /* CC_DEST = source, CC_SRC = shift */ + CC_OP_SARB, /* CC_DEST = source, CC_SRC = shift */ + CC_OP_SARW, /* CC_DEST = source, CC_SRC = shift */ CC_OP_SAR, /* CC_DEST = source, CC_SRC = shift */ }; @@ -191,6 +206,12 @@ ISA revisions mentioned. */ enum m68k_features { + M68K_FEATURE_M68000, + M68K_FEATURE_M68020, + M68K_FEATURE_M68020_40, /* Features common to 68020 - 68040 */ + M68K_FEATURE_M68040, + M68K_FEATURE_M68020_60, /* Feature common to 68020 - 68060 */ + M68K_FEATURE_M68060, M68K_FEATURE_CF_ISA_A, M68K_FEATURE_CF_ISA_B, /* (ISA B or C). */ M68K_FEATURE_CF_ISA_APLUSC, /* BIT/BITREV, FF1, STRLDSR (ISA A+ or C). */ @@ -201,7 +222,9 @@ M68K_FEATURE_CF_EMAC_B, /* Revision B EMAC (dual accumulate). */ M68K_FEATURE_USP, /* User Stack Pointer. (ISA A+, B or C). */ M68K_FEATURE_EXT_FULL, /* 68020+ full extension word. */ - M68K_FEATURE_WORD_INDEX /* word sized address index registers. */ + M68K_FEATURE_WORD_INDEX, /* word sized address index registers. */ + M68K_FEATURE_SCALED_INDEX, /* scaled address index registers. */ + M68K_FEATURE_FPU }; static inline int m68k_feature(CPUM68KState *env, int feature) @@ -212,8 +235,8 @@ void register_m68k_insns (CPUM68KState *env); #ifdef CONFIG_USER_ONLY -/* Linux uses 8k pages. */ -#define TARGET_PAGE_BITS 13 +/* Linux uses 4k pages. */ +#define TARGET_PAGE_BITS 12 #else /* Smallest TLB entry size is 1k. */ #define TARGET_PAGE_BITS 10 --- target-m68k/exec.h +++ target-m68k/exec.h @@ -48,6 +48,10 @@ float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1); void helper_movec(CPUM68KState *env, int reg, uint32_t val); +extern const uint8_t rox8_table[64]; +extern const uint8_t rox16_table[64]; +extern const uint8_t rox32_table[64]; + void cpu_loop_exit(void); static inline int cpu_halted(CPUState *env) { --- target-m68k/helper.c +++ target-m68k/helper.c @@ -27,6 +27,10 @@ #include "exec-all.h" enum m68k_cpuid { + M68K_CPUID_M68000, + M68K_CPUID_M68020, + M68K_CPUID_M68040, + M68K_CPUID_M68060, M68K_CPUID_M5206, M68K_CPUID_M5208, M68K_CPUID_CFV4E, @@ -39,6 +43,10 @@ }; static m68k_def_t m68k_cpu_defs[] = { + {"m68000", M68K_CPUID_M68000}, + {"m68020", M68K_CPUID_M68020}, + {"m68040", M68K_CPUID_M68040}, + {"m68060", M68K_CPUID_M68060}, {"m5206", M68K_CPUID_M5206}, {"m5208", M68K_CPUID_M5208}, {"cfv4e", M68K_CPUID_CFV4E}, @@ -63,12 +71,41 @@ return 1; switch (def->id) { + case M68K_CPUID_M68000: + m68k_set_feature(env, M68K_FEATURE_M68000); + m68k_set_feature(env, M68K_FEATURE_USP); + m68k_set_feature(env, M68K_FEATURE_WORD_INDEX); + break; + case M68K_CPUID_M68020: + case M68K_CPUID_M68040: + m68k_set_feature(env, M68K_FEATURE_M68000); + m68k_set_feature(env, M68K_FEATURE_M68020_40); + m68k_set_feature(env, M68K_FEATURE_M68020_60); + m68k_set_feature(env, M68K_FEATURE_USP); + m68k_set_feature(env, M68K_FEATURE_BRAL); + m68k_set_feature(env, M68K_FEATURE_EXT_FULL); + m68k_set_feature(env, M68K_FEATURE_WORD_INDEX); + m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX); + m68k_set_feature(env, M68K_FEATURE_FPU); + break; + case M68K_CPUID_M68060: + m68k_set_feature(env, M68K_FEATURE_M68000); + m68k_set_feature(env, M68K_FEATURE_M68020_60); + m68k_set_feature(env, M68K_FEATURE_USP); + m68k_set_feature(env, M68K_FEATURE_BRAL); + m68k_set_feature(env, M68K_FEATURE_EXT_FULL); + m68k_set_feature(env, M68K_FEATURE_WORD_INDEX); + m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX); + m68k_set_feature(env, M68K_FEATURE_FPU); + break; case M68K_CPUID_M5206: m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); + m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX); break; case M68K_CPUID_M5208: m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC); + m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX); m68k_set_feature(env, M68K_FEATURE_BRAL); m68k_set_feature(env, M68K_FEATURE_CF_EMAC); m68k_set_feature(env, M68K_FEATURE_USP); @@ -76,12 +113,19 @@ case M68K_CPUID_CFV4E: m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); + m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX); m68k_set_feature(env, M68K_FEATURE_BRAL); m68k_set_feature(env, M68K_FEATURE_CF_FPU); m68k_set_feature(env, M68K_FEATURE_CF_EMAC); m68k_set_feature(env, M68K_FEATURE_USP); break; case M68K_CPUID_ANY: + m68k_set_feature(env, M68K_FEATURE_M68000); + m68k_set_feature(env, M68K_FEATURE_M68020); + m68k_set_feature(env, M68K_FEATURE_M68020_40); + m68k_set_feature(env, M68K_FEATURE_M68040); + m68k_set_feature(env, M68K_FEATURE_M68020_60); + m68k_set_feature(env, M68K_FEATURE_M68060); m68k_set_feature(env, M68K_FEATURE_CF_ISA_A); m68k_set_feature(env, M68K_FEATURE_CF_ISA_B); m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC); @@ -93,6 +137,7 @@ m68k_set_feature(env, M68K_FEATURE_CF_EMAC_B); m68k_set_feature(env, M68K_FEATURE_USP); m68k_set_feature(env, M68K_FEATURE_EXT_FULL); + m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX); m68k_set_feature(env, M68K_FEATURE_WORD_INDEX); break; } @@ -102,6 +147,42 @@ return 0; } +/* modulo 33 table */ +const uint8_t rox32_table[64] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23, + 24,25,26,27,28,29,30,31, + 32, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9,10,11,12,13,14, + 15,16,17,18,19,20,21,22, + 23,24,25,26,27,28,29,30, +}; + +/* modulo 17 table */ +const uint8_t rox16_table[64] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9,10,11,12,13,14,15, + 16, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9,10,11,12,13,14, + 15,16, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9,10,11,12,13, + 14,15,16, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9,10,11,12, +}; + +/* modulo 9 table */ +const uint8_t rox8_table[64] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 0, 1, 2, + 3, 4, 5, 6, 7, 8, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 0, +}; + void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op) { int flags; @@ -127,6 +208,66 @@ flags |= CCF_V; \ } while (0) +#define SET_FLAGS_ADD(type, utype) do { \ + SET_NZ((type)dest); \ + if ((utype) dest < (utype) src) \ + flags |= CCF_C; \ + tmp = dest - src; \ + if ((1u << (sizeof(type) * 8 - 1)) & (src ^ dest) & (tmp ^ src)) \ + flags |= CCF_V; \ + } while (0) + +#define SET_FLAGS_ADDX(type, utype) do { \ + SET_NZ((type)dest); \ + if ((utype) dest <= (utype) src) \ + flags |= CCF_C; \ + tmp = dest - src - 1; \ + if ((1u << (sizeof(type) * 8 - 1)) & (src ^ dest) & (tmp ^ src)) \ + flags |= CCF_V; \ + } while (0) + +#define SET_FLAGS_SUBX(type, utype) do { \ + SET_NZ((type)dest); \ + tmp = dest + src + 1; \ + if ((utype) dest <= (utype) src) \ + flags |= CCF_C; \ + if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \ + flags |= CCF_V; \ + } while (0) + +#define SET_FLAGS_SHL(type) do { \ + if (src >= sizeof(type) * 8) { \ + SET_NZ(0); \ + } else { \ + tmp = dest << src; \ + SET_NZ((type)tmp); \ + } \ + if (src && src <= sizeof(type) * 8 && (dest & (1 << (sizeof(type) * 8 - src)))) \ + flags |= CCF_C; \ + } while (0) + +#define SET_FLAGS_SHR(type) do { \ + if (src >= sizeof(type) * 8) { \ + SET_NZ(0); \ + } else { \ + tmp = dest >> src; \ + SET_NZ((type)tmp); \ + } \ + if (src && src <= sizeof(type) * 8 && ((dest >> (src - 1)) & 1)) \ + flags |= CCF_C; \ + } while (0) + +#define SET_FLAGS_SAR(type) do { \ + if (src >= sizeof(type) * 8) { \ + SET_NZ(-((type)dest < 0)); \ + } else { \ + tmp = dest >> src; \ + SET_NZ((type)tmp); \ + } \ + if (src && src <= sizeof(type) * 8 && (((type)dest >> (src - 1)) & 1)) \ + flags |= CCF_C; \ + } while (0) + flags = 0; src = env->cc_src; dest = env->cc_dest; @@ -137,68 +278,68 @@ case CC_OP_LOGIC: SET_NZ(dest); break; + case CC_OP_ADDB: + SET_FLAGS_ADD(int8_t, uint8_t); + break; + case CC_OP_ADDW: + SET_FLAGS_ADD(int16_t, uint16_t); + break; case CC_OP_ADD: - SET_NZ(dest); - if (dest < src) - flags |= CCF_C; - tmp = dest - src; - if (HIGHBIT & (src ^ dest) & ~(tmp ^ src)) - flags |= CCF_V; + SET_FLAGS_ADD(int32_t, uint32_t); + break; + case CC_OP_SUBB: + SET_FLAGS_SUB(int8_t, uint8_t); + break; + case CC_OP_SUBW: + SET_FLAGS_SUB(int16_t, uint16_t); break; case CC_OP_SUB: SET_FLAGS_SUB(int32_t, uint32_t); break; - case CC_OP_CMPB: - SET_FLAGS_SUB(int8_t, uint8_t); + case CC_OP_ADDXB: + SET_FLAGS_ADDX(int8_t, uint8_t); break; - case CC_OP_CMPW: - SET_FLAGS_SUB(int16_t, uint16_t); + case CC_OP_ADDXW: + SET_FLAGS_ADDX(int16_t, uint16_t); break; case CC_OP_ADDX: - SET_NZ(dest); - if (dest <= src) - flags |= CCF_C; - tmp = dest - src - 1; - if (HIGHBIT & (src ^ dest) & ~(tmp ^ src)) - flags |= CCF_V; + SET_FLAGS_ADDX(int32_t, uint32_t); + break; + case CC_OP_SUBXB: + SET_FLAGS_SUBX(int8_t, uint8_t); + break; + case CC_OP_SUBXW: + SET_FLAGS_SUBX(int16_t, uint16_t); break; case CC_OP_SUBX: - SET_NZ(dest); - tmp = dest + src + 1; - if (tmp <= src) - flags |= CCF_C; - if (HIGHBIT & (tmp ^ dest) & (tmp ^ src)) - flags |= CCF_V; + SET_FLAGS_SUBX(int32_t, uint32_t); + break; + case CC_OP_SHLB: + SET_FLAGS_SHL(int8_t); + break; + case CC_OP_SHLW: + SET_FLAGS_SHL(int16_t); break; case CC_OP_SHL: - if (src >= 32) { - SET_NZ(0); - } else { - tmp = dest << src; - SET_NZ(tmp); - } - if (src && src <= 32 && (dest & (1 << (32 - src)))) - flags |= CCF_C; + SET_FLAGS_SHL(int32_t); + break; + case CC_OP_SHRB: + SET_FLAGS_SHR(int8_t); + break; + case CC_OP_SHRW: + SET_FLAGS_SHR(int16_t); break; case CC_OP_SHR: - if (src >= 32) { - SET_NZ(0); - } else { - tmp = dest >> src; - SET_NZ(tmp); - } - if (src && src <= 32 && ((dest >> (src - 1)) & 1)) - flags |= CCF_C; + SET_FLAGS_SHR(int32_t); + break; + case CC_OP_SARB: + SET_FLAGS_SAR(int8_t); + break; + case CC_OP_SARW: + SET_FLAGS_SAR(int16_t); break; case CC_OP_SAR: - if (src >= 32) { - SET_NZ(-1); - } else { - tmp = (int32_t)dest >> src; - SET_NZ(tmp); - } - if (src && src <= 32 && (((int32_t)dest >> (src - 1)) & 1)) - flags |= CCF_C; + SET_FLAGS_SAR(int32_t); break; default: cpu_abort(env, "Bad CC_OP %d", cc_op); --- target-m68k/op-hacks.h +++ target-m68k/op-hacks.h @@ -89,6 +89,36 @@ gen_op_sar_cc(val, gen_im32(shift)); } +static inline void gen_op_shl8_im_cc(int dest, int src, int shift) +{ + gen_op_shl8_cc(dest, src, gen_im32(shift)); +} + +static inline void gen_op_shr8_im_cc(int dest, int src, int shift) +{ + gen_op_shr8_cc(dest, src, gen_im32(shift)); +} + +static inline void gen_op_sar8_im_cc(int dest, int src, int shift) +{ + gen_op_sar8_cc(dest, src, gen_im32(shift)); +} + +static inline void gen_op_shl16_im_cc(int dest, int src, int shift) +{ + gen_op_shl16_cc(dest, src, gen_im32(shift)); +} + +static inline void gen_op_shr16_im_cc(int dest, int src, int shift) +{ + gen_op_shr16_cc(dest, src, gen_im32(shift)); +} + +static inline void gen_op_sar16_im_cc(int dest, int src, int shift) +{ + gen_op_sar16_cc(dest, src, gen_im32(shift)); +} + #ifdef USE_DIRECT_JUMP #define TBPARAM(x) #else --- target-m68k/op.c +++ target-m68k/op.c @@ -136,6 +136,76 @@ FORCE_RET(); } +OP(mulu32_cc) +{ + uint32_t op2 = get_op(PARAM2); + uint32_t op3 = get_op(PARAM3); + uint64_t result = (uint32_t)op2 * op3; + uint32_t flags; + set_op(PARAM1, result); + flags = 0; + if (result >> 32) + flags |= CCF_V; + if ((uint32_t)result == 0) + flags |= CCF_Z; + if ((int32_t)result < 0) + flags |= CCF_N; + env->cc_dest = flags; + FORCE_RET(); +} + +OP(muls32_cc) +{ + int32_t op2 = get_op(PARAM2); + int32_t op3 = get_op(PARAM3); + int64_t result = (int32_t)op2 * op3; + uint32_t flags; + set_op(PARAM1, result); + flags = 0; + if (result != (int64_t)(int32_t)result) + flags |= CCF_V; + if ((uint32_t)result == 0) + flags |= CCF_Z; + if ((int32_t)result < 0) + flags |= CCF_N; + env->cc_dest = flags; + FORCE_RET(); +} + +OP(mulu64) +{ + uint32_t op2 = get_op(PARAM2); + uint32_t op3 = get_op(PARAM3); + uint64_t result = (uint64_t)op2 * op3; + uint32_t flags; + set_op(PARAM1, result); + env->quadh = result >> 32; + flags = 0; + if (result == 0) + flags |= CCF_Z; + if ((int64_t)result < 0) + flags |= CCF_N; + env->cc_dest = flags; + FORCE_RET(); +} + +OP(muls64) +{ + int32_t op2 = get_op(PARAM2); + int32_t op3 = get_op(PARAM3); + int64_t result = (uint64_t)op2 * op3; + uint32_t flags; + set_op(PARAM1, result); + env->quadh = result >> 32; + flags = 0; + if (result == 0) + flags |= CCF_Z; + if (result < 0) + flags |= CCF_N; + env->cc_dest = flags; + FORCE_RET(); +} + OP(not32) { uint32_t arg = get_op(PARAM2); @@ -180,6 +250,22 @@ FORCE_RET(); } +OP(bfffo) +{ + uint32_t arg = get_op(PARAM2); + int width = get_op(PARAM3); + int n; + uint32_t mask; + mask = 0x80000000; + for (n = 0; n < width; n++) { + if (arg & mask) + break; + mask >>= 1; + } + set_op(PARAM1, n); + FORCE_RET(); +} + OP(subx_cc) { uint32_t op1 = get_op(PARAM1); @@ -253,14 +339,60 @@ FORCE_RET(); } +OP(shl8_cc) +{ + uint8_t op2 = get_op(PARAM2); + uint8_t op3 = get_op(PARAM3); + uint8_t result; + if (op3 < 8) + result = op2 << op3; + else + result = 0; + set_op(PARAM1, result); + if (op3 > 0) { + if (op3 <= 8) + env->cc_x = (op2 << (op3 - 1)) & 0x80; + else + env->cc_x = 0; + } + FORCE_RET(); +} + +OP(shl16_cc) +{ + uint16_t op2 = get_op(PARAM2); + uint16_t op3 = get_op(PARAM3); + uint16_t result; + if (op3 < 16) + result = op2 << op3; + else + result = 0; + set_op(PARAM1, result); + if (op3 > 0) { + if (op3 <= 16) + env->cc_x = (op2 << (op3 - 1)) & 0x8000; + else + env->cc_x = 0; + } + FORCE_RET(); +} + OP(shl_cc) { uint32_t op1 = get_op(PARAM1); uint32_t op2 = get_op(PARAM2); uint32_t result; - result = op1 << op2; + if (op2 < 32) + result = op1 << op2; + else + result = 0; set_op(PARAM1, result); - env->cc_x = (op1 << (op2 - 1)) & 1; + if (op2 > 0) { + if (op2 <= 32) + env->cc_x = (op1 << (op2 - 1)) & 0x80000000; + else + env->cc_x = 0; + } FORCE_RET(); } @@ -279,9 +411,55 @@ uint32_t op1 = get_op(PARAM1); uint32_t op2 = get_op(PARAM2); uint32_t result; - result = op1 >> op2; + if (op2 < 32) + result = op1 >> op2; + else + result = 0; set_op(PARAM1, result); - env->cc_x = (op1 >> (op2 - 1)) & 1; + if (op2 > 0) { + if (op2 <= 32) + env->cc_x = (op1 >> (op2 - 1)) & 1; + else + env->cc_x = 0; + } + FORCE_RET(); +} + +OP(shr8_cc) +{ + uint8_t op2 = get_op(PARAM2); + uint8_t op3 = get_op(PARAM3); + uint8_t result; + if (op3 < 8) + result = op2 >> op3; + else + result = 0; + set_op(PARAM1, result); + if (op3 > 0) { + if (op3 <= 8) + env->cc_x = (op2 >> (op3 - 1)) & 1; + else + env->cc_x = 0; + } + FORCE_RET(); +} + +OP(shr16_cc) +{ + uint16_t op2 = get_op(PARAM2); + uint16_t op3 = get_op(PARAM3); + uint16_t result; + if (op3 < 16) + result = op2 >> op3; + else + result = 0; + set_op(PARAM1, result); + if (op3 > 0) { + if (op3 <= 16) + env->cc_x = (op2 >> (op3 - 1)) & 1; + else + env->cc_x = 0; + } FORCE_RET(); } @@ -300,12 +478,199 @@ int32_t op1 = get_op(PARAM1); uint32_t op2 = get_op(PARAM2); uint32_t result; - result = op1 >> op2; + if (op2 < 32) + result = op1 >> op2; + else + result = 0; + set_op(PARAM1, result); + if (op2 > 0) { + if (op2 <= 32) + env->cc_x = (op1 >> (op2 - 1)) & 1; + else + env->cc_x = 0; + } + FORCE_RET(); +} + +OP(sar8_cc) +{ + int8_t op2 = get_op(PARAM2); + uint8_t op3 = get_op(PARAM3); + uint8_t result; + if (op3 < 8) + result = op2 >> op3; + else + result = 0; + set_op(PARAM1, result); + if (op3 > 0) { + if (op3 <= 8) + env->cc_x = (op2 >> (op3 - 1)) & 1; + else + env->cc_x = 0; + } + FORCE_RET(); +} + +OP(sar16_cc) +{ + int16_t op2 = get_op(PARAM2); + uint16_t op3 = get_op(PARAM3); + uint16_t result; + if (op3 < 16) + result = op2 >> op3; + else + result = 0; set_op(PARAM1, result); - env->cc_x = (op1 >> (op2 - 1)) & 1; + if (op3 > 0) { + if (op3 <= 16) + env->cc_x = (op2 >> (op3 - 1)) & 1; + else + env->cc_x = 0; + } FORCE_RET(); } +OP(rol32) +{ + uint32_t op2 = get_op(PARAM2); + uint32_t op3 = get_op(PARAM3); + uint32_t result; + result = (op2 << op3) | (op2 >> (32 - op3)); + set_op(PARAM1, result); + FORCE_RET(); +} + +OP(ror32) +{ + uint32_t op2 = get_op(PARAM2); + uint32_t op3 = get_op(PARAM3); + uint32_t result; + result = (op2 >> op3) | (op2 << (32 - op3)); + set_op(PARAM1, result); + FORCE_RET(); +} + +#define OP_ROL(type, bits) \ +OP(glue(glue(rol,bits),_cc)) \ +{ \ + type op2 = get_op(PARAM2); \ + uint32_t op3 = get_op(PARAM3); \ + type result; \ + uint32_t flags; \ + int count = op3 & (bits - 1); \ + if (count) \ + result = (op2 << count) | (op2 >> (bits - count)); \ + else \ + result = op2; \ + set_op(PARAM1, result); \ + flags = 0; \ + if (result == 0) \ + flags |= CCF_Z; \ + if (result & (1 << (bits - 1))) \ + flags |= CCF_N; \ + if (op3 && result & 1) \ + flags |= CCF_C; \ + env->cc_dest = flags; \ + FORCE_RET(); \ +} +OP_ROL(uint8_t, 8) +OP_ROL(uint16_t, 16) +OP_ROL(uint32_t, 32) + +#define OP_ROR(type, bits) \ +OP(glue(glue(ror,bits),_cc)) \ +{ \ + type op2 = get_op(PARAM2); \ + uint32_t op3 = get_op(PARAM3); \ + type result; \ + uint32_t flags; \ + int count = op3 & (bits - 1); \ + if (count) \ + result = (op2 >> count) | (op2 << (bits - count)); \ + else \ + result = op2; \ + set_op(PARAM1, result); \ + flags = 0; \ + if (result == 0) \ + flags |= CCF_Z; \ + if (result & (1 << (bits - 1))) \ + flags |= CCF_N; \ + if (op3 && result & (1 << (bits - 1))) \ + flags |= CCF_C; \ + env->cc_dest = flags; \ + FORCE_RET(); \ +} +OP_ROR(uint8_t, 8) +OP_ROR(uint16_t, 16) +OP_ROR(uint32_t, 32) + +#define OP_ROXR(type, bits) \ +OP(glue(glue(roxr,bits),_cc)) \ +{ \ + type op2 = get_op(PARAM2); \ + uint32_t op3 = get_op(PARAM3); \ + type result; \ + uint32_t flags; \ + int count = op3; \ + if (bits == 8) count = rox8_table[count]; \ + if (bits == 16) count = rox16_table[count]; \ + if (bits == 32) count = rox32_table[count]; \ + if (count) { \ + result = (op2 >> count) | ((type)env->cc_x << (bits - count)); \ + if (count > 1) \ + result |= op2 << (bits + 1 - count); \ + env->cc_x = (op2 >> (count - 1)) & 1; \ + } else \ + result = op2; \ + set_op(PARAM1, result); \ + flags = 0; \ + if (result == 0) \ + flags |= CCF_Z; \ + if (result & (1 << (bits - 1))) \ + flags |= CCF_N; \ + if (env->cc_x) \ + flags |= CCF_C; \ + env->cc_dest = flags; \ + FORCE_RET(); \ +} +OP_ROXR(uint8_t, 8) +OP_ROXR(uint16_t, 16) +OP_ROXR(uint32_t, 32) + +#define OP_ROXL(type, bits) \ +OP(glue(glue(roxl,bits),_cc)) \ +{ \ + type op2 = get_op(PARAM2); \ + uint32_t op3 = get_op(PARAM3); \ + type result; \ + uint32_t flags; \ + int count; \ + count = op3; \ + if (bits == 8) count = rox8_table[count]; \ + if (bits == 16) count = rox16_table[count]; \ + if (bits == 32) count = rox32_table[count]; \ + if (count) { \ + result = (op2 << count) | ((type)env->cc_x << (count - 1)); \ + if (count > 1) \ + result |= op2 >> (bits + 1 - count); \ + env->cc_x = (op2 >> (bits - count)) & 1; \ + } else \ + result = op2; \ + set_op(PARAM1, result); \ + flags = 0; \ + if (result == 0) \ + flags |= CCF_Z; \ + if (result & (1 << (bits - 1))) \ + flags |= CCF_N; \ + if (env->cc_x) \ + flags |= CCF_C; \ + env->cc_dest = flags; \ + FORCE_RET(); \ +} +OP_ROXL(uint8_t, 8) +OP_ROXL(uint16_t, 16) +OP_ROXL(uint32_t, 32) + /* Value extend. */ OP(ext8u32) @@ -361,14 +726,17 @@ /* Avoid using a PARAM1 of zero. This breaks dyngen because it uses the address of a symbol, and gcc knows symbols can't have address zero. */ - if (PARAM1 == 2 && quot > 0xffff) + if (PARAM1 == 1 && quot > 0xffff) flags |= CCF_V; if (quot == 0) flags |= CCF_Z; else if ((int32_t)quot < 0) flags |= CCF_N; - env->div1 = quot; - env->div2 = rem; + /* Don't modify destination if overflow occured. */ + if ((flags & CCF_V) == 0) { + env->div1 = quot; + env->div2 = rem; + } env->cc_dest = flags; FORCE_RET(); } @@ -379,7 +747,7 @@ int32_t den; int32_t quot; int32_t rem; - int32_t flags; + uint32_t flags; num = env->div1; den = env->div2; @@ -388,14 +756,78 @@ quot = num / den; rem = num % den; flags = 0; - if (PARAM1 == 2 && quot != (int16_t)quot) + if (PARAM1 == 1 && quot != (int16_t)quot) + flags |= CCF_V; + if (quot == 0) + flags |= CCF_Z; + else if (quot < 0) + flags |= CCF_N; + /* Don't modify destination if overflow occured. */ + if ((flags & CCF_V) == 0) { + env->div1 = quot; + env->div2 = rem; + } + env->cc_dest = flags; + FORCE_RET(); +} + +OP(divu64) +{ + uint32_t num; + uint32_t den; + uint64_t quot; + uint32_t rem; + uint32_t flags; + + num = env->div1; + den = env->div2; + /* ??? This needs to make sure the throwing location is accurate. */ + if (den == 0) + RAISE_EXCEPTION(EXCP_DIV0); + quot = (num | ((uint64_t)env->quadh << 32)) / den; + rem = (num | ((uint64_t)env->quadh << 32)) % den; + flags = 0; + if (quot > 0xffffffff) + flags |= CCF_V; + if (quot == 0) + flags |= CCF_Z; + else if ((int64_t)quot < 0) + flags |= CCF_N; + /* Don't modify destination if overflow occured. */ + if ((flags & CCF_V) == 0) { + env->div1 = quot; + env->div2 = rem; + } + env->cc_dest = flags; + FORCE_RET(); +} + +OP(divs64) +{ + int32_t num; + int32_t den; + int64_t quot; + int32_t rem; + uint32_t flags; + + num = env->div1; + den = env->div2; + if (den == 0) + RAISE_EXCEPTION(EXCP_DIV0); + quot = (num | ((int64_t)env->quadh << 32)) / den; + rem = (num | ((int64_t)env->quadh << 32)) % den; + flags = 0; + if (quot != (int32_t)quot) flags |= CCF_V; if (quot == 0) flags |= CCF_Z; else if (quot < 0) flags |= CCF_N; - env->div1 = quot; - env->div2 = rem; + /* Don't modify destination if overflow occured. */ + if ((flags & CCF_V) == 0) { + env->div1 = quot; + env->div2 = rem; + } env->cc_dest = flags; FORCE_RET(); } --- target-m68k/qregs.def +++ target-m68k/qregs.def @@ -32,6 +32,7 @@ DEFO32(CC_X, cc_x) DEFO32(DIV1, div1) DEFO32(DIV2, div2) +DEFO32(QUADH, quadh) DEFO32(EXCEPTION, exception_index) DEFO32(MACSR, macsr) DEFO32(MAC_MASK, mac_mask) --- target-m68k/translate.c +++ target-m68k/translate.c @@ -250,6 +250,9 @@ if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX)) return -1; + if (!m68k_feature(s->env, M68K_FEATURE_SCALED_INDEX)) + ext &= ~(3 << 9); + if (ext & 0x100) { /* full extension word format */ if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL)) @@ -258,7 +261,7 @@ if ((ext & 0x30) > 0x10) { /* base displacement */ if ((ext & 0x30) == 0x20) { - bd = (int16_t)lduw_code(s->pc); + bd = ldsw_code(s->pc); s->pc += 2; } else { bd = read_im32(s); @@ -307,7 +310,7 @@ if ((ext & 3) > 1) { /* outer displacement */ if ((ext & 3) == 2) { - od = (int16_t)lduw_code(s->pc); + od = ldsw_code(s->pc); s->pc += 2; } else { od = read_im32(s); @@ -366,6 +369,25 @@ } } +static inline int insn_opsize(int insn, int pos) +{ + switch ((insn >> pos) & 3) { + case 0: return OS_BYTE; + case 1: return OS_WORD; + case 2: return OS_LONG; + default: abort(); + } +} + +#define SET_CC_OP(opsize, op) do { \ + switch (opsize) { \ + case OS_BYTE: s->cc_op = CC_OP_##op##B; break; \ + case OS_WORD: s->cc_op = CC_OP_##op##W; break; \ + case OS_LONG: s->cc_op = CC_OP_##op; break; \ + default: abort(); \ + } \ + } while (0) + /* Assign value to a register. If the width is less than the register width only the low part of the register is set. */ static void gen_partset_reg(int opsize, int reg, int val) @@ -881,8 +903,27 @@ ext = lduw_code(s->pc); s->pc += 2; - if (ext & 0x87f8) { - gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); + if (ext & 0x400) { + if (!m68k_feature(s->env, M68K_FEATURE_M68020_40)) { + gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); + return; + } + num = DREG(ext, 12); + reg = DREG(ext, 0); + gen_op_mov32(QREG_DIV1, num); + gen_op_mov32(QREG_QUADH, reg); + SRC_EA(den, OS_LONG, 0, NULL); + gen_op_mov32(QREG_DIV2, den); + if (ext & 0x0800) { + gen_op_divs64(); + } else { + gen_op_divu64(); + } + gen_op_mov32 (num, QREG_DIV1); + if (num != reg) + gen_op_mov32 (reg, QREG_DIV2); + gen_op_flags_set(); + s->cc_op = CC_OP_FLAGS; return; } num = DREG(ext, 12); @@ -895,13 +936,10 @@ } else { gen_op_divu(2); } - if (num == reg) { - /* div */ - gen_op_mov32 (reg, QREG_DIV1); - } else { - /* rem */ - gen_op_mov32 (reg, QREG_DIV2); - } + if (num == reg || m68k_feature(s->env, M68K_FEATURE_M68020_60)) + gen_op_mov32 (num, QREG_DIV1); + if (num != reg) + gen_op_mov32 (reg, QREG_DIV2); gen_op_flags_set(); s->cc_op = CC_OP_FLAGS; } @@ -914,31 +952,33 @@ int tmp; int addr; int add; + int opsize; add = (insn & 0x4000) != 0; + opsize = insn_opsize(insn, 6); reg = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); if (insn & 0x100) { - SRC_EA(tmp, OS_LONG, 0, &addr); + SRC_EA(tmp, opsize, -1, &addr); src = reg; } else { tmp = reg; - SRC_EA(src, OS_LONG, 0, NULL); + SRC_EA(src, opsize, -1, NULL); } if (add) { gen_op_add32(dest, tmp, src); gen_op_update_xflag_lt(dest, src); - s->cc_op = CC_OP_ADD; + SET_CC_OP(opsize, ADD); } else { gen_op_update_xflag_lt(tmp, src); gen_op_sub32(dest, tmp, src); - s->cc_op = CC_OP_SUB; + SET_CC_OP(opsize, SUB); } gen_op_update_cc_add(dest, src); if (insn & 0x100) { - DEST_EA(insn, OS_LONG, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } else { - gen_op_mov32(reg, dest); + gen_partset_reg(opsize, reg, dest); } } @@ -1065,6 +1105,8 @@ int reg; int tmp; int is_load; + int opsize; + int incr; mask = lduw_code(s->pc); s->pc += 2; @@ -1076,21 +1118,40 @@ addr = gen_new_qreg(QMODE_I32); gen_op_mov32(addr, tmp); is_load = ((insn & 0x0400) != 0); - for (i = 0; i < 16; i++, mask >>= 1) { - if (mask & 1) { - if (i < 8) - reg = DREG(i, 0); - else - reg = AREG(i, 0); - if (is_load) { - tmp = gen_load(s, OS_LONG, addr, 0); - gen_op_mov32(reg, tmp); - } else { - gen_store(s, OS_LONG, addr, reg); - } - if (mask != 1) - gen_op_add32(addr, addr, gen_im32(4)); - } + opsize = (insn & 0x40) != 0 ? OS_LONG : OS_WORD; + incr = gen_im32(opsize_bytes(opsize)); + if (!is_load && (insn & 070) == 040) { + for (i = 15; i >= 0; i--, mask >>= 1) { + if (mask & 1) { + if (i < 8) + reg = DREG(i, 0); + else + reg = AREG(i, 0); + gen_store(s, opsize, addr, reg); + if (mask != 1) + gen_op_sub32(addr, addr, incr); + } + } + gen_op_mov32(AREG(insn, 0), addr); + } else { + for (i = 0; i < 16; i++, mask >>= 1) { + if (mask & 1) { + if (i < 8) + reg = DREG(i, 0); + else + reg = AREG(i, 0); + if (is_load) { + tmp = gen_load(s, opsize, addr, 1); + gen_op_mov32(reg, tmp); + } else { + gen_store(s, opsize, addr, reg); + } + if (mask != 1 || (insn & 070) == 030) + gen_op_add32(addr, addr, incr); + } + } + if ((insn & 070) == 030) + gen_op_mov32(AREG(insn, 0), addr); } } @@ -1158,10 +1219,26 @@ int dest; int src2; int addr; + int opsize; op = (insn >> 9) & 7; - SRC_EA(src1, OS_LONG, 0, (op == 6) ? NULL : &addr); - src2 = gen_im32(read_im32(s)); + opsize = insn_opsize(insn, 6); + switch (opsize) { + case OS_BYTE: + src2 = gen_im32(ldsb_code(s->pc + 1)); + s->pc += 2; + break; + case OS_WORD: + src2 = gen_im32(ldsw_code(s->pc)); + s->pc += 2; + break; + case OS_LONG: + src2 = gen_im32(read_im32(s)); + break; + default: + abort(); + } + SRC_EA(src1, opsize, -1, (op == 6) ? NULL : &addr); dest = gen_new_qreg(QMODE_I32); switch (op) { case 0: /* ori */ @@ -1177,14 +1254,14 @@ gen_op_update_xflag_lt(dest, src2); gen_op_sub32(dest, dest, src2); gen_op_update_cc_add(dest, src2); - s->cc_op = CC_OP_SUB; + SET_CC_OP(opsize, SUB); break; case 3: /* addi */ gen_op_mov32(dest, src1); gen_op_add32(dest, dest, src2); gen_op_update_cc_add(dest, src2); gen_op_update_xflag_lt(dest, src2); - s->cc_op = CC_OP_ADD; + SET_CC_OP(opsize, ADD); break; case 5: /* eori */ gen_op_xor32(dest, src1, src2); @@ -1194,13 +1271,13 @@ gen_op_mov32(dest, src1); gen_op_sub32(dest, dest, src2); gen_op_update_cc_add(dest, src2); - s->cc_op = CC_OP_SUB; + SET_CC_OP(opsize, SUB); break; default: abort(); } if (op != 6) { - DEST_EA(insn, OS_LONG, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } } @@ -1290,19 +1367,7 @@ { int opsize; - switch ((insn >> 6) & 3) { - case 0: /* clr.b */ - opsize = OS_BYTE; - break; - case 1: /* clr.w */ - opsize = OS_WORD; - break; - case 2: /* clr.l */ - opsize = OS_LONG; - break; - default: - abort(); - } + opsize = insn_opsize(insn, 6); DEST_EA(insn, opsize, gen_im32(0), NULL); gen_logic_cc(s, gen_im32(0)); } @@ -1331,17 +1396,20 @@ DISAS_INSN(neg) { - int reg; int src1; + int dest; + int addr; + int opsize; - reg = DREG(insn, 0); - src1 = gen_new_qreg(QMODE_I32); - gen_op_mov32(src1, reg); - gen_op_neg32(reg, src1); - s->cc_op = CC_OP_SUB; - gen_op_update_cc_add(reg, src1); - gen_op_update_xflag_lt(gen_im32(0), src1); - s->cc_op = CC_OP_SUB; + opsize = insn_opsize(insn, 6); + SRC_EA(src1, opsize, -1, &addr); + dest = gen_new_qreg(QMODE_I32); + gen_op_neg32(dest, src1); + DEST_EA(insn, opsize, dest, &addr); + SET_CC_OP(opsize, SUB); + gen_op_update_cc_add(src1, dest); + gen_op_update_xflag_lt(gen_im32(0), dest); + SET_CC_OP(opsize, SUB); } static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) @@ -1390,11 +1458,17 @@ DISAS_INSN(not) { - int reg; + int src1; + int dest; + int addr; + int opsize; - reg = DREG(insn, 0); - gen_op_not32(reg, reg); - gen_logic_cc(s, reg); + opsize = insn_opsize(insn, 6); + SRC_EA(src1, opsize, -1, &addr); + dest = gen_new_qreg(QMODE_I32); + gen_op_not32(dest, src1); + DEST_EA(insn, opsize, dest, &addr); + gen_logic_cc(s, dest); } DISAS_INSN(swap) @@ -1452,19 +1526,7 @@ int opsize; int tmp; - switch ((insn >> 6) & 3) { - case 0: /* tst.b */ - opsize = OS_BYTE; - break; - case 1: /* tst.w */ - opsize = OS_WORD; - break; - case 2: /* tst.l */ - opsize = OS_LONG; - break; - default: - abort(); - } + opsize = insn_opsize(insn, 6); SRC_EA(tmp, opsize, -1, NULL); gen_logic_cc(s, tmp); } @@ -1493,28 +1555,149 @@ DEST_EA(insn, OS_BYTE, dest, &addr); } +DISAS_INSN(cas) +{ + int opsize; + int src; + int tmp; + int ext; + int regc; + int regu; + int l1, l2; + int addr; + + ext = lduw_code(s->pc); + s->pc += 2; + regc = DREG(ext, 0); + regu = DREG(ext, 6); + tmp = gen_new_qreg(QMODE_I32); + switch ((insn >> 9) & 3) { + case 1: + opsize = OS_BYTE; + break; + case 2: + opsize = OS_WORD; + break; + case 3: + opsize = OS_LONG; + break; + default: + abort(); + } + SRC_EA(src, opsize, -1, &addr); + gen_op_sub32(tmp, src, regc); + gen_op_update_cc_add(tmp, regc); + SET_CC_OP(opsize, SUB); + l1 = gen_new_label(); + l2 = gen_new_label(); + gen_jmpcc(s, 6, l1); + DEST_EA(insn, opsize, regu, &addr); + gen_op_jmp(l2); + gen_set_label(l1); + gen_partset_reg(opsize, regc, src); + gen_set_label(l2); +} + +DISAS_INSN(cas2) +{ + int opsize; + int src1, src2; + int cmp1, cmp2; + int ext1, ext2; + int regc1, regc2; + int regu1, regu2; + int tmp; + int l1, l2; + + ext1 = lduw_code(s->pc); + s->pc += 2; + regc1 = DREG(ext1, 0); + regu1 = DREG(ext1, 6); + if (ext1 & 0x8000) + src1 = AREG(ext1, 12); + else + src1 = DREG(ext1, 12); + ext2 = lduw_code(s->pc); + s->pc += 2; + regc2 = DREG(ext2, 0); + regu2 = DREG(ext2, 6); + if (ext2 & 0x8000) + src2 = AREG(ext2, 12); + else + src2 = DREG(ext2, 12); + if (insn & 0x200) + opsize = OS_LONG; + else + opsize = OS_WORD; + l1 = gen_new_label(); + l2 = gen_new_label(); + tmp = gen_new_qreg(QMODE_I32); + cmp1 = gen_load(s, opsize, src1, 1); + cmp2 = gen_load(s, opsize, src2, 1); + gen_op_sub32(tmp, cmp1, regc1); + gen_op_update_cc_add(tmp, regc1); + SET_CC_OP(opsize, SUB); + gen_jmpcc(s, 6, l1); + gen_op_sub32(tmp, cmp2, regc2); + gen_op_update_cc_add(tmp, regc2); + SET_CC_OP(opsize, SUB); + gen_jmpcc(s, 6, l1); + gen_store(s, opsize, src1, regu1); + gen_store(s, opsize, src2, regu2); + gen_op_jmp(l2); + gen_set_label(l1); + gen_partset_reg(opsize, regc1, cmp1); + gen_partset_reg(opsize, regc2, cmp2); + gen_set_label(l2); +} + DISAS_INSN(mull) { uint16_t ext; int reg; int src1; int dest; + int regh; /* The upper 32 bits of the product are discarded, so muls.l and mulu.l are functionally equivalent. */ ext = lduw_code(s->pc); s->pc += 2; - if (ext & 0x87ff) { - gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); - return; + if (ext & 0x400) { + if (!m68k_feature(s->env, M68K_FEATURE_M68020_40)) { + gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); + return; + } + reg = DREG(ext, 12); + regh = DREG(ext, 0); + SRC_EA(src1, OS_LONG, 0, NULL); + dest = gen_new_qreg(QMODE_I32); + if (ext & 0x800) + gen_op_muls64(dest, src1, reg); + else + gen_op_mulu64(dest, src1, reg); + gen_op_mov32(reg, dest); + gen_op_mov32(regh, QREG_QUADH); + gen_op_flags_set(); + s->cc_op = CC_OP_FLAGS; + return; } reg = DREG(ext, 12); SRC_EA(src1, OS_LONG, 0, NULL); dest = gen_new_qreg(QMODE_I32); - gen_op_mul32(dest, src1, reg); + if (m68k_feature(s->env, M68K_FEATURE_M68000)) { + if (ext & 0x800) + gen_op_muls32_cc(dest, src1, reg); + else + gen_op_mulu32_cc(dest, src1, reg); + gen_op_flags_set(); + s->cc_op = CC_OP_FLAGS; + } else { + gen_op_mul32(dest, src1, reg); + /* Unlike m68k, coldfire always clears the overflow bit. */ + gen_logic_cc(s, dest); + } gen_op_mov32(reg, dest); - /* Unlike m68k, coldfire always clears the overflow bit. */ - gen_logic_cc(s, dest); } DISAS_INSN(link) @@ -1534,6 +1717,22 @@ gen_op_add32(QREG_SP, tmp, gen_im32(offset)); } +DISAS_INSN(linkl) +{ + int32_t offset; + int reg; + int tmp; + + offset = read_im32(s); + reg = AREG(insn, 0); + tmp = gen_new_qreg(QMODE_I32); + gen_op_sub32(tmp, QREG_SP, gen_im32(4)); + gen_store(s, OS_LONG, tmp, reg); + if (reg != QREG_SP) + gen_op_mov32(reg, tmp); + gen_op_add32(QREG_SP, tmp, gen_im32(offset)); +} + DISAS_INSN(unlk) { int src; @@ -1586,8 +1785,14 @@ int dest; int val; int addr; + int opsize; - SRC_EA(src1, OS_LONG, 0, &addr); + if ((insn & 070) == 010) { + /* Operation on address register is always long. */ + opsize = OS_LONG; + } else + opsize = insn_opsize(insn, 6); + SRC_EA(src1, opsize, -1, &addr); val = (insn >> 9) & 7; if (val == 0) val = 8; @@ -1606,15 +1811,15 @@ if (insn & 0x0100) { gen_op_update_xflag_lt(dest, src2); gen_op_sub32(dest, dest, src2); - s->cc_op = CC_OP_SUB; + SET_CC_OP(opsize, SUB); } else { gen_op_add32(dest, dest, src2); gen_op_update_xflag_lt(dest, src2); - s->cc_op = CC_OP_ADD; + SET_CC_OP(opsize, ADD); } gen_op_update_cc_add(dest, src2); } - DEST_EA(insn, OS_LONG, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } DISAS_INSN(tpf) @@ -1633,6 +1838,47 @@ } } +DISAS_INSN(scc_mem) +{ + int l1; + int cond; + int dest; + + l1 = gen_new_label(); + cond = (insn >> 8) & 0xf; + dest = gen_new_qreg(QMODE_I32); + gen_op_mov32(dest, gen_im32(0)); + gen_jmpcc(s, cond ^ 1, l1); + gen_op_mov32(dest, gen_im32(0xff)); + gen_set_label(l1); + DEST_EA(insn, OS_BYTE, dest, NULL); +} + +DISAS_INSN(dbcc) +{ + int l1; + int reg; + int tmp; + int16_t offset; + uint32_t base; + + reg = DREG(insn, 0); + base = s->pc; + offset = ldsw_code(s->pc); + s->pc += 2; + l1 = gen_new_label(); + gen_jmpcc(s, (insn >> 8) & 0xf, l1); + tmp = gen_new_qreg(QMODE_I32); + gen_op_ext16s32(tmp, reg); + gen_op_set_T0_z32(tmp); + gen_op_add32(tmp, tmp, gen_im32(-1)); + gen_partset_reg(OS_WORD, reg, tmp); + gen_op_jmp_T0(l1); + gen_jmp_tb(s, 1, base + offset); + gen_set_label(l1); + gen_jmp_tb(s, 0, s->pc); +} + DISAS_INSN(branch) { int32_t offset; @@ -1698,17 +1944,19 @@ int dest; int src; int addr; + int opsize; + opsize = insn_opsize(insn, 6); reg = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); if (insn & 0x100) { - SRC_EA(src, OS_LONG, 0, &addr); + SRC_EA(src, opsize, -1, &addr); gen_op_or32(dest, src, reg); - DEST_EA(insn, OS_LONG, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } else { - SRC_EA(src, OS_LONG, 0, NULL); + SRC_EA(src, opsize, 0, NULL); gen_op_or32(dest, src, reg); - gen_op_mov32(reg, dest); + gen_partset_reg(opsize, reg, dest); } gen_logic_cc(s, dest); } @@ -1718,7 +1966,7 @@ int src; int reg; - SRC_EA(src, OS_LONG, 0, NULL); + SRC_EA(src, (insn & 0x100) ? OS_LONG : OS_WORD, -1, NULL); reg = AREG(insn, 9); gen_op_sub32(reg, reg, src); } @@ -1763,34 +2011,18 @@ DISAS_INSN(cmp) { - int op; int src; int reg; int dest; int opsize; - op = (insn >> 6) & 3; - switch (op) { - case 0: /* cmp.b */ - opsize = OS_BYTE; - s->cc_op = CC_OP_CMPB; - break; - case 1: /* cmp.w */ - opsize = OS_WORD; - s->cc_op = CC_OP_CMPW; - break; - case 2: /* cmp.l */ - opsize = OS_LONG; - s->cc_op = CC_OP_SUB; - break; - default: - abort(); - } + opsize = insn_opsize(insn, 6); SRC_EA(src, opsize, -1, NULL); reg = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); gen_op_sub32(dest, reg, src); gen_op_update_cc_add(dest, src); + SET_CC_OP(opsize, SUB); } DISAS_INSN(cmpa) @@ -1810,7 +2042,7 @@ dest = gen_new_qreg(QMODE_I32); gen_op_sub32(dest, reg, src); gen_op_update_cc_add(dest, src); - s->cc_op = CC_OP_SUB; + SET_CC_OP(opsize, SUB); } DISAS_INSN(eor) @@ -1819,13 +2051,15 @@ int reg; int dest; int addr; + int opsize; - SRC_EA(src, OS_LONG, 0, &addr); + opsize = insn_opsize(insn, 6); + SRC_EA(src, opsize, -1, &addr); reg = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); gen_op_xor32(dest, src, reg); gen_logic_cc(s, dest); - DEST_EA(insn, OS_LONG, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } DISAS_INSN(and) @@ -1834,17 +2068,19 @@ int reg; int dest; int addr; + int opsize; + opsize = insn_opsize(insn, 6); reg = DREG(insn, 9); dest = gen_new_qreg(QMODE_I32); if (insn & 0x100) { - SRC_EA(src, OS_LONG, 0, &addr); + SRC_EA(src, opsize, -1, &addr); gen_op_and32(dest, src, reg); - DEST_EA(insn, OS_LONG, dest, &addr); + DEST_EA(insn, opsize, dest, &addr); } else { - SRC_EA(src, OS_LONG, 0, NULL); + SRC_EA(src, opsize, -1, NULL); gen_op_and32(dest, src, reg); - gen_op_mov32(reg, dest); + gen_partset_reg(opsize, reg, dest); } gen_logic_cc(s, dest); } @@ -1854,7 +2090,7 @@ int src; int reg; - SRC_EA(src, OS_LONG, 0, NULL); + SRC_EA(src, (insn & 0x100) ? OS_LONG : OS_WORD, -1, NULL); reg = AREG(insn, 9); gen_op_add32(reg, reg, src); } @@ -1907,6 +2143,58 @@ } } +DISAS_INSN(shift8_im) +{ + int reg; + int dest; + int tmp; + + reg = DREG(insn, 0); + tmp = (insn >> 9) & 7; + if (tmp == 0) + tmp = 8; + dest = gen_new_qreg(QMODE_I32); + if (insn & 0x100) { + gen_op_shl8_im_cc(dest, reg, tmp); + s->cc_op = CC_OP_SHLB; + } else { + if (insn & 8) { + gen_op_shr8_im_cc(dest, reg, tmp); + s->cc_op = CC_OP_SHRB; + } else { + gen_op_sar8_im_cc(dest, reg, tmp); + s->cc_op = CC_OP_SARB; + } + } + gen_partset_reg(OS_BYTE, reg, dest); +} + +DISAS_INSN(shift16_im) +{ + int reg; + int dest; + int tmp; + + reg = DREG(insn, 0); + tmp = (insn >> 9) & 7; + if (tmp == 0) + tmp = 8; + dest = gen_new_qreg(QMODE_I32); + if (insn & 0x100) { + gen_op_shl16_im_cc(dest, reg, tmp); + s->cc_op = CC_OP_SHLW; + } else { + if (insn & 8) { + gen_op_shr16_im_cc(dest, reg, tmp); + s->cc_op = CC_OP_SHRW; + } else { + gen_op_sar16_im_cc(dest, reg, tmp); + s->cc_op = CC_OP_SARW; + } + } + gen_partset_reg(OS_WORD, reg, dest); +} + DISAS_INSN(shift_reg) { int reg; @@ -1931,6 +2219,603 @@ } } +DISAS_INSN(shift8_reg) +{ + int reg; + int src; + int dest; + int tmp; + + reg = DREG(insn, 0); + src = DREG(insn, 9); + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, src, gen_im32(63)); + dest = gen_new_qreg(QMODE_I32); + if (insn & 0x100) { + gen_op_shl8_cc(dest, reg, tmp); + s->cc_op = CC_OP_SHLB; + } else { + if (insn & 8) { + gen_op_shr8_cc(dest, reg, tmp); + s->cc_op = CC_OP_SHRB; + } else { + gen_op_sar8_cc(dest, reg, tmp); + s->cc_op = CC_OP_SARB; + } + } + gen_partset_reg(OS_BYTE, reg, dest); +} + +DISAS_INSN(shift16_reg) +{ + int reg; + int src; + int dest; + int tmp; + + reg = DREG(insn, 0); + src = DREG(insn, 9); + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, src, gen_im32(63)); + dest = gen_new_qreg(QMODE_I32); + if (insn & 0x100) { + gen_op_shl16_cc(dest, reg, tmp); + s->cc_op = CC_OP_SHLW; + } else { + if (insn & 8) { + gen_op_shr16_cc(dest, reg, tmp); + s->cc_op = CC_OP_SHRW; + } else { + gen_op_sar16_cc(dest, reg, tmp); + s->cc_op = CC_OP_SARW; + } + } + gen_partset_reg(OS_WORD, reg, dest); +} + +DISAS_INSN(shift_mem) +{ + int src; + int dest; + int addr; + + SRC_EA(src, OS_WORD, 0, &addr); + dest = gen_new_qreg(QMODE_I32); + if (insn & 0x100) { + gen_op_shl16_im_cc(dest, src, 1); + s->cc_op = CC_OP_SHLW; + } else { + if (insn & 8) { + gen_op_shr16_im_cc(dest, src, 1); + s->cc_op = CC_OP_SHRW; + } else { + gen_op_sar16_im_cc(dest, src, 1); + s->cc_op = CC_OP_SARW; + } + } + DEST_EA(insn, OS_WORD, dest, &addr); +} + +DISAS_INSN(rotate_im) +{ + int reg; + int tmp; + + reg = DREG(insn, 0); + tmp = (insn >> 9) & 7; + if (tmp == 0) + tmp = 8; + tmp = gen_im32(tmp); + if (insn & 8) { + if (insn & 0x100) { + gen_op_rol32_cc(reg, reg, tmp); + } else { + gen_op_ror32_cc(reg, reg, tmp); + } + } else { + if (insn & 0x100) { + gen_op_roxl32_cc(reg, reg, tmp); + } else { + gen_op_roxr32_cc(reg, reg, tmp); + } + } + gen_op_flags_set(); + s->cc_op = CC_OP_FLAGS; +} + +DISAS_INSN(rotate8_im) +{ + int reg; + int dest; + int tmp; + + reg = DREG(insn, 0); + tmp = (insn >> 9) & 7; + if (tmp == 0) + tmp = 8; + tmp = gen_im32(tmp); + dest = gen_new_qreg(QMODE_I32); + if (insn & 8) { + if (insn & 0x100) { + gen_op_rol8_cc(dest, reg, tmp); + } else { + gen_op_ror8_cc(dest, reg, tmp); + } + } else { + if (insn & 0x100) { + gen_op_roxl8_cc(dest, reg, tmp); + } else { + gen_op_roxr8_cc(dest, reg, tmp); + } + } + gen_op_flags_set(); + s->cc_op = CC_OP_FLAGS; + gen_partset_reg(OS_BYTE, reg, dest); +} + +DISAS_INSN(rotate16_im) +{ + int reg; + int dest; + int tmp; + + reg = DREG(insn, 0); + tmp = (insn >> 9) & 7; + if (tmp == 0) + tmp = 8; + tmp = gen_im32(tmp); + dest = gen_new_qreg(QMODE_I32); + if (insn & 8) { + if (insn & 0x100) { + gen_op_rol16_cc(dest, reg, tmp); + } else { + gen_op_ror16_cc(dest, reg, tmp); + } + } else { + if (insn & 0x100) { + gen_op_roxl16_cc(dest, reg, tmp); + } else { + gen_op_roxr16_cc(dest, reg, tmp); + } + } + gen_op_flags_set(); + s->cc_op = CC_OP_FLAGS; + gen_partset_reg(OS_WORD, reg, dest); +} + +DISAS_INSN(rotate_reg) +{ + int reg; + int src; + int tmp; + + reg = DREG(insn, 0); + src = DREG(insn, 9); + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, src, gen_im32(63)); + if (insn & 8) { + if (insn & 0x100) { + gen_op_rol32_cc(reg, reg, tmp); + } else { + gen_op_ror32_cc(reg, reg, tmp); + } + } else { + if (insn & 0x100) { + gen_op_roxl32_cc(reg, reg, tmp); + } else { + gen_op_roxr32_cc(reg, reg, tmp); + } + } + gen_op_flags_set(); + s->cc_op = CC_OP_FLAGS; +} + +DISAS_INSN(rotate8_reg) +{ + int reg; + int src; + int dest; + int tmp; + + reg = DREG(insn, 0); + src = DREG(insn, 9); + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, src, gen_im32(63)); + dest = gen_new_qreg(QMODE_I32); + if (insn & 8) { + if (insn & 0x100) { + gen_op_rol8_cc(dest, reg, tmp); + } else { + gen_op_ror8_cc(dest, reg, tmp); + } + } else { + if (insn & 0x100) { + gen_op_roxl8_cc(dest, reg, tmp); + } else { + gen_op_roxr8_cc(dest, reg, tmp); + } + } + gen_op_flags_set(); + s->cc_op = CC_OP_FLAGS; + gen_partset_reg(OS_BYTE, reg, dest); +} + +DISAS_INSN(rotate16_reg) +{ + int reg; + int src; + int dest; + int tmp; + + reg = DREG(insn, 0); + src = DREG(insn, 9); + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, src, gen_im32(63)); + dest = gen_new_qreg(QMODE_I32); + if (insn & 8) { + if (insn & 0x100) { + gen_op_rol16_cc(dest, reg, tmp); + } else { + gen_op_ror16_cc(dest, reg, tmp); + } + } else { + if (insn & 0x100) { + gen_op_roxl16_cc(dest, reg, tmp); + } else { + gen_op_roxr16_cc(dest, reg, tmp); + } + } + gen_op_flags_set(); + s->cc_op = CC_OP_FLAGS; + gen_partset_reg(OS_WORD, reg, dest); +} + +DISAS_INSN(rotate_mem) +{ + int src; + int dest; + int addr; + + SRC_EA(src, OS_WORD, 0, &addr); + dest = gen_new_qreg(QMODE_I32); + if (insn & 8) { + if (insn & 0x100) { + gen_op_rol16_cc(dest, src, gen_im32(1)); + } else { + gen_op_ror16_cc(dest, src, gen_im32(1)); + } + } else { + if (insn & 0x100) { + gen_op_roxl16_cc(dest, src, gen_im32(1)); + } else { + gen_op_roxr16_cc(dest, src, gen_im32(1)); + } + } + gen_op_flags_set(); + s->cc_op = CC_OP_FLAGS; + DEST_EA(insn, OS_WORD, dest, &addr); +} + +DISAS_INSN(bitfield_reg) +{ + uint16_t ext; + int tmp; + int tmp1; + int reg; + int offset; + int width; + int op; + int reg2; + uint32_t mask; + + reg = DREG(insn, 0); + op = (insn >> 8) & 7; + ext = lduw_code(s->pc); + s->pc += 2; + if ((ext & 0x820) == 0) { + /* constant offset and width */ + offset = (ext >> 6) & 31; + width = (ext & 31); + if (width == 0) + width = 32; + reg2 = DREG(ext, 12); + mask = 0xffffffff << (32 - width); + if (offset > 0) + mask = (mask >> offset) | (mask << (32 - offset)); + tmp = gen_new_qreg(QMODE_I32); + gen_op_and32(tmp, reg, gen_im32(mask)); + if (offset > 0) { + tmp1 = gen_new_qreg(QMODE_I32); + gen_op_rol32(tmp1, tmp, gen_im32(offset)); + } else + tmp1 = tmp; + gen_logic_cc(s, tmp1); + switch (op) { + case 0: /* bftst */ + break; + case 1: /* bfextu */ + if (offset + width != 32) + gen_op_rol32(reg2, tmp, gen_im32((offset + width) & 31)); + else + gen_op_mov32(reg2, tmp); + break; + case 2: /* bfchg */ + gen_op_xor32(reg, reg, gen_im32(mask)); + break; + case 3: /* bfexts */ + if (offset > 0) + gen_op_rol32(reg2, tmp, gen_im32(offset)); + if (width < 32) + gen_op_sar32(reg2, reg2, gen_im32(32 - width)); + break; + case 4: /* bfclr */ + gen_op_and32(reg, reg, gen_im32(~mask)); + break; + case 5: /* bfffo */ + if (offset > 0) + gen_op_rol32(reg2, tmp, gen_im32(offset)); + gen_op_bfffo(tmp, tmp, gen_im32(width)); + gen_op_add32(reg2, tmp, gen_im32(offset)); + break; + case 6: /* bfset */ + gen_op_or32(reg, reg, gen_im32(mask)); + break; + case 7: /* bfins */ + if (width == 32) { + if (offset > 0) + gen_op_ror32(reg, reg2, gen_im32(offset)); + else + gen_op_mov32(reg, reg2); + } else { + gen_op_and32(tmp, reg2, gen_im32((1u << width) - 1)); + if (offset + width != 32) + gen_op_ror32(tmp, tmp, gen_im32((offset + width) & 31)); + gen_op_and32(reg, reg, gen_im32(~mask)); + gen_op_or32(reg, reg, tmp); + } + break; + } + return; + } + /* Not yet implemented */ + gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); +} + +/* Generate a load from a bitfield. */ +static void gen_bitfield_load(DisasContext *s, int addr, int endpos, + int *val1, int *val2) +{ + int tmp; + + if (endpos <= 8) + *val1 = gen_load(s, OS_BYTE, addr, 0); + else if (endpos <= 24) { + *val1 = gen_load(s, OS_WORD, addr, 0); + if (endpos > 16) { + tmp = gen_new_qreg(QMODE_I32); + gen_op_add32(tmp, addr, gen_im32(2)); + *val2 = gen_load(s, OS_BYTE, tmp, 0); + } + } else { + *val1 = gen_load(s, OS_LONG, addr, 0); + if (endpos > 32) { + tmp = gen_new_qreg(QMODE_I32); + gen_op_add32(tmp, addr, gen_im32(4)); + *val2 = gen_load(s, OS_BYTE, tmp, 0); + } + } +} + +/* Generate a store to a bitfield. */ +static void gen_bitfield_store(DisasContext *s, int addr, int endpos, + int val1, int val2) +{ + int tmp; + + if (endpos <= 8) + gen_store(s, OS_BYTE, addr, val1); + else if (endpos <= 24) { + gen_store(s, OS_WORD, addr, val1); + if (endpos > 16) { + tmp = gen_new_qreg(QMODE_I32); + gen_op_add32(tmp, addr, gen_im32(2)); + gen_store(s, OS_BYTE, tmp, val2); + } + } else { + gen_store(s, OS_LONG, addr, val1); + if (endpos > 32) { + tmp = gen_new_qreg(QMODE_I32); + gen_op_add32(tmp, addr, gen_im32(4)); + gen_store(s, OS_BYTE, tmp, val2); + } + } +} + +static int gen_bitfield_cc(DisasContext *s, int offset, int width, + int val1, int val2) +{ + int dest; + int tmp; + + dest = gen_new_qreg(QMODE_I32); + if (offset + width <= 8) + gen_op_shl32(dest, val1, gen_im32(24 + offset)); + else if (offset + width <= 24) { + gen_op_shl32(dest, val1, gen_im32(16 + offset)); + if (offset + width > 16) { + tmp = gen_new_qreg(QMODE_I32); + gen_op_shl32(tmp, val2, gen_im32(8 + offset)); + gen_op_or32(dest, dest, tmp); + } + } else { + gen_op_shl32(dest, val1, gen_im32(offset)); + if (offset + width > 32) { + tmp = gen_new_qreg(QMODE_I32); + gen_op_shr32(tmp, val2, gen_im32(offset)); + gen_op_or32(dest, dest, tmp); + } + } + gen_op_and32(dest, dest, gen_im32(0xffffffff << (32 - width))); + gen_logic_cc(s, dest); + return dest; +} + +static void gen_bitfield_op(int offset, int width, int op, int val1, int val2) +{ + uint32_t mask1; + uint32_t mask2; + int endpos = offset + width; + + if (endpos <= 8) { + mask1 = (0xff >> offset) & (0xff << (8 - endpos)); + mask2 = 0; + } else if (endpos <= 16) { + mask1 = (0xffff >> offset) & (0xffff << (16 - endpos)); + mask2 = 0; + } else if (endpos <= 24) { + mask1 = 0xffffff >> offset; + mask2 = 0xff & (0xff << (24 - endpos)); + } else if (endpos <= 32) { + mask1 = (0xffffffff >> offset) & (0xffffffff << (32 - endpos)); + mask2 = 0; + } else { + mask1 = 0xffffffff >> offset; + mask2 = 0xff & (0xff << (40 - endpos)); + } + switch (op) { + case 2: /* bfchg */ + gen_op_xor32(val1, val1, gen_im32(mask1)); + if (mask2) + gen_op_xor32(val2, val2, gen_im32(mask2)); + break; + case 4: /* bfclr */ + gen_op_and32(val1, val1, gen_im32(~mask1)); + if (mask2) + gen_op_and32(val2, val2, gen_im32(~mask2)); + break; + case 6: /* bfset */ + gen_op_or32(val1, val1, gen_im32(mask1)); + if (mask2) + gen_op_or32(val2, val2, gen_im32(mask2)); + break; + } +} + +static void gen_bitfield_ins(int offset, int width, int src, + int val1, int val2) +{ + int tmp; + int endpos = offset + width; + + tmp = gen_new_qreg(QMODE_I32); + if (width < 32) { + gen_op_and32(tmp, src, gen_im32((1u << width) - 1)); + } else + gen_op_mov32(tmp, src); + if (endpos <= 8) { + if (endpos < 8) + gen_op_shl32(tmp, tmp, gen_im32(8 - endpos)); + gen_op_or32(val1, val1, tmp); + } else if (endpos <= 16) { + if (endpos < 16) + gen_op_shl32(tmp, tmp, gen_im32(16 - endpos)); + gen_op_or32(val1, val1, tmp); + } else if (endpos <= 24) { + gen_op_shr32(tmp, tmp, gen_im32(endpos - 16)); + gen_op_or32(val1, val1, tmp); + gen_op_and32(tmp, src, gen_im32((1u << (endpos - 16)) - 1)); + if (endpos < 24) + gen_op_shl32(tmp, tmp, gen_im32(24 - endpos)); + gen_op_or32(val2, val2, tmp); + } else if (endpos <= 32) { + if (endpos < 32) + gen_op_shl32(tmp, tmp, gen_im32(32 - endpos)); + gen_op_or32(val1, val1, tmp); + } else { + gen_op_shr32(tmp, tmp, gen_im32(endpos - 32)); + gen_op_or32(val1, val1, tmp); + gen_op_and32(tmp, src, gen_im32((1u << (endpos - 32)) - 1)); + gen_op_shr32(tmp, tmp, gen_im32(32 - endpos)); + gen_op_or32(val2, val2, tmp); + } +} + +DISAS_INSN(bitfield_mem) +{ + uint16_t ext; + int val; + int val1, val2; + int src; + int offset; + int width; + int op; + int reg; + int addr; + uint32_t mask; + + op = (insn >> 8) & 7; + ext = lduw_code(s->pc); + s->pc += 2; + src = gen_lea(s, insn, OS_LONG); + if (src == -1) { + gen_addr_fault(s); + return; + } + if ((ext & 0x820) == 0) { + /* constant offset and width */ + offset = (ext >> 6) & 31; + width = (ext & 31); + if (width == 0) + width = 32; + reg = DREG(ext, 12); + mask = 0xffffffff << (32 - width); + addr = gen_new_qreg(QMODE_I32); + if (offset > 7) { + gen_op_add32(addr, src, gen_im32(offset >> 3)); + offset &= 7; + } else + gen_op_mov32(addr, src); + if (offset > 0) + mask <<= 32 - offset; + gen_bitfield_load(s, addr, offset + width, &val1, &val2); + val = gen_bitfield_cc(s, offset, width, val1, val2); + switch (op) { + case 0: /* bftst */ + break; + case 1: /* bfextu */ + if (width < 32) + gen_op_shr32(reg, val, gen_im32(32 - width)); + else + gen_op_mov32(reg, val); + break; + case 3: /* bfexts */ + if (width < 32) + gen_op_sar32(reg, val, gen_im32(32 - width)); + else + gen_op_mov32(reg, val); + break; + case 5: /* bfffo */ + gen_op_bfffo(val, val, gen_im32(width)); + gen_op_add32(reg, val, gen_im32(offset)); + break; + case 2: /* bfchg */ + case 4: /* bfclr */ + case 6: /* bfset */ + gen_bitfield_op(offset, width, op, val1, val2); + gen_bitfield_store(s, addr, offset + width, val1, val2); + break; + case 7: /* bfins */ + gen_bitfield_op(offset, width, 4, val1, val2); + gen_bitfield_ins(offset, width, reg, val1, val2); + gen_bitfield_store(s, addr, offset + width, val1, val2); + break; + } + return; + } + /* Not yet implemented */ + gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); +} + DISAS_INSN(ff1) { int reg; @@ -2194,17 +3079,42 @@ case 7: { int addr; + int incr; uint16_t mask; - if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0) + if ((ext & 0xf00) != 0 || (ext & 0xff) == 0) goto undef; - src = gen_lea(s, insn, OS_LONG); - if (src == -1) { - gen_addr_fault(s); - return; - } + if ((ext & 0x1000) == 0 && !m68k_feature(s->env, M68K_FEATURE_FPU)) + goto undef; + if ((insn & 070) == 040) + src = AREG(insn, 0); + else { + src = gen_lea(s, insn, OS_LONG); + if (src == -1) { + gen_addr_fault(s); + return; + } + } addr = gen_new_qreg(QMODE_I32); gen_op_mov32(addr, src); mask = 0x80; + if (m68k_feature(s->env, M68K_FEATURE_FPU)) + incr = gen_im32(12); + else + incr = gen_im32(8); + if ((ext & (1 << 13)) && (insn & 070) == 040) { + dest = QREG_F7; + while (mask) { + if (ext & mask) { + s->is_mem = 1; + gen_op_sub32(addr, addr, incr); + gen_op_mov32(AREG(insn, 0), addr); + gen_st(s, f64, addr, dest); + } + mask >>= 1; + dest++; + } + return; + } dest = QREG_F0; while (mask) { if (ext & mask) { @@ -2216,8 +3126,11 @@ /* load */ gen_ld(s, f64, dest, addr); } - if (ext & (mask - 1)) - gen_op_add32(addr, addr, gen_im32(8)); + if (ext & (mask - 1) || (insn & 070) == 030) { + gen_op_add32(addr, addr, incr); + if ((insn & 070) == 030) + gen_op_mov32(AREG(insn, 0), addr); + } } mask >>= 1; dest++; @@ -2293,6 +3206,12 @@ case 0x23: case 0x63: case 0x67: /* fmul */ gen_op_mulf64(res, res, src); break; + case 0x24: /* fsgldiv */ + gen_op_divf64(res, res, src); + break; + case 0x27: /* fsglmul */ + gen_op_mulf64(res, res, src); + break; case 0x28: case 0x68: case 0x6c: /* fsub */ gen_op_subf64(res, res, src); break; @@ -2759,85 +3678,158 @@ register_opcode(disas_##name, 0x##opcode, 0x##mask); \ } while(0) INSN(undef, 0000, 0000, CF_ISA_A); + INSN(undef, 0000, 0000, M68000); INSN(arith_im, 0080, fff8, CF_ISA_A); + INSN(arith_im, 0000, ff00, M68000); + INSN(undef, 00c0, ffc0, M68000); INSN(bitrev, 00c0, fff8, CF_ISA_APLUSC); INSN(bitop_reg, 0100, f1c0, CF_ISA_A); + INSN(bitop_reg, 0100, f1c0, M68000); INSN(bitop_reg, 0140, f1c0, CF_ISA_A); + INSN(bitop_reg, 0140, f1c0, M68000); INSN(bitop_reg, 0180, f1c0, CF_ISA_A); + INSN(bitop_reg, 0180, f1c0, M68000); INSN(bitop_reg, 01c0, f1c0, CF_ISA_A); + INSN(bitop_reg, 01c0, f1c0, M68000); INSN(arith_im, 0280, fff8, CF_ISA_A); + INSN(arith_im, 0200, ff00, M68000); + INSN(undef, 02c0, ffc0, M68000); INSN(byterev, 02c0, fff8, CF_ISA_APLUSC); INSN(arith_im, 0480, fff8, CF_ISA_A); + INSN(arith_im, 0400, ff00, M68000); + INSN(undef, 04c0, ffc0, M68000); INSN(ff1, 04c0, fff8, CF_ISA_APLUSC); INSN(arith_im, 0680, fff8, CF_ISA_A); + INSN(arith_im, 0600, ff00, M68000); + INSN(undef, 06c0, ffc0, M68000); + INSN(cas, 08c0, f8c0, M68020_60); + INSN(cas2, 0cfc, fdff, M68020_40); INSN(bitop_im, 0800, ffc0, CF_ISA_A); + INSN(bitop_im, 0800, ffc0, M68000); INSN(bitop_im, 0840, ffc0, CF_ISA_A); + INSN(bitop_im, 0840, ffc0, M68000); INSN(bitop_im, 0880, ffc0, CF_ISA_A); + INSN(bitop_im, 0880, ffc0, M68000); INSN(bitop_im, 08c0, ffc0, CF_ISA_A); + INSN(bitop_im, 08c0, ffc0, M68000); INSN(arith_im, 0a80, fff8, CF_ISA_A); + INSN(arith_im, 0a00, ff00, M68000); + INSN(undef, 0ac0, ffc0, M68000); INSN(arith_im, 0c00, ff38, CF_ISA_A); + INSN(arith_im, 0c00, ff00, M68000); + INSN(undef, 0cc0, ffc0, M68000); INSN(move, 1000, f000, CF_ISA_A); + INSN(move, 1000, f000, M68000); INSN(move, 2000, f000, CF_ISA_A); + INSN(move, 2000, f000, M68000); INSN(move, 3000, f000, CF_ISA_A); + INSN(move, 3000, f000, M68000); INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC); INSN(negx, 4080, fff8, CF_ISA_A); + INSN(negx, 4000, ff00, M68000); + INSN(undef, 40c0, ffc0, M68000); INSN(move_from_sr, 40c0, fff8, CF_ISA_A); + INSN(move_from_sr, 40c0, fff8, M68000); INSN(lea, 41c0, f1c0, CF_ISA_A); + INSN(lea, 41c0, f1c0, M68000); INSN(clr, 4200, ff00, CF_ISA_A); + INSN(clr, 4200, ff00, M68000); INSN(undef, 42c0, ffc0, CF_ISA_A); + INSN(undef, 42c0, ffc0, M68000); INSN(move_from_ccr, 42c0, fff8, CF_ISA_A); INSN(neg, 4480, fff8, CF_ISA_A); + INSN(neg, 4400, ff00, M68000); + INSN(undef, 44c0, ffc0, M68000); INSN(move_to_ccr, 44c0, ffc0, CF_ISA_A); + INSN(move_to_ccr, 44c0, ffc0, M68000); INSN(not, 4680, fff8, CF_ISA_A); + INSN(not, 4600, ff00, M68000); + INSN(undef, 46c0, ffc0, M68000); INSN(move_to_sr, 46c0, ffc0, CF_ISA_A); + INSN(linkl, 4808, fff8, M68020_60); INSN(pea, 4840, ffc0, CF_ISA_A); + INSN(pea, 4840, ffc0, M68000); INSN(swap, 4840, fff8, CF_ISA_A); + INSN(swap, 4840, fff8, M68000); INSN(movem, 48c0, fbc0, CF_ISA_A); + INSN(movem, 48c0, fbc0, M68000); INSN(ext, 4880, fff8, CF_ISA_A); + INSN(ext, 4880, fff8, M68000); INSN(ext, 48c0, fff8, CF_ISA_A); + INSN(ext, 48c0, fff8, M68000); INSN(ext, 49c0, fff8, CF_ISA_A); + INSN(ext, 49c0, fff8, M68000); INSN(tst, 4a00, ff00, CF_ISA_A); + INSN(tst, 4a00, ff00, M68000); INSN(tas, 4ac0, ffc0, CF_ISA_B); + INSN(tas, 4ac0, ffc0, M68000); INSN(halt, 4ac8, ffff, CF_ISA_A); INSN(pulse, 4acc, ffff, CF_ISA_A); INSN(illegal, 4afc, ffff, CF_ISA_A); + INSN(illegal, 4afc, ffff, M68000); INSN(mull, 4c00, ffc0, CF_ISA_A); + INSN(mull, 4c00, ffc0, M68020_60); INSN(divl, 4c40, ffc0, CF_ISA_A); + INSN(divl, 4c40, ffc0, M68020_60); INSN(sats, 4c80, fff8, CF_ISA_B); INSN(trap, 4e40, fff0, CF_ISA_A); + INSN(trap, 4e40, fff0, M68000); INSN(link, 4e50, fff8, CF_ISA_A); + INSN(link, 4e50, fff8, M68000); INSN(unlk, 4e58, fff8, CF_ISA_A); + INSN(unlk, 4e58, fff8, M68000); INSN(move_to_usp, 4e60, fff8, USP); INSN(move_from_usp, 4e68, fff8, USP); INSN(nop, 4e71, ffff, CF_ISA_A); + INSN(nop, 4e71, ffff, M68000); INSN(stop, 4e72, ffff, CF_ISA_A); + INSN(stop, 4e72, ffff, M68000); INSN(rte, 4e73, ffff, CF_ISA_A); + INSN(rte, 4e73, ffff, M68000); INSN(rts, 4e75, ffff, CF_ISA_A); + INSN(rts, 4e75, ffff, M68000); INSN(movec, 4e7b, ffff, CF_ISA_A); INSN(jump, 4e80, ffc0, CF_ISA_A); + INSN(jump, 4e80, ffc0, M68000); INSN(jump, 4ec0, ffc0, CF_ISA_A); - INSN(addsubq, 5180, f1c0, CF_ISA_A); + INSN(jump, 4ec0, ffc0, M68000); + INSN(addsubq, 5080, f0c0, CF_ISA_A); + INSN(addsubq, 5000, f080, M68000); + INSN(addsubq, 5080, f0c0, M68000); INSN(scc, 50c0, f0f8, CF_ISA_A); - INSN(addsubq, 5080, f1c0, CF_ISA_A); + INSN(scc_mem, 50c0, f0c0, M68000); + INSN(scc, 50c0, f0f8, M68000); + INSN(dbcc, 50c8, f0f8, M68000); INSN(tpf, 51f8, fff8, CF_ISA_A); /* Branch instructions. */ INSN(branch, 6000, f000, CF_ISA_A); + INSN(branch, 6000, f000, M68000); /* Disable long branch instructions, then add back the ones we want. */ INSN(undef, 60ff, f0ff, CF_ISA_A); /* All long branches. */ + INSN(undef, 60ff, f0ff, M68000); /* All long branches. */ INSN(branch, 60ff, f0ff, CF_ISA_B); INSN(undef, 60ff, ffff, CF_ISA_B); /* bra.l */ INSN(branch, 60ff, ffff, BRAL); + INSN(branch, 60ff, f0ff, M68020_60); INSN(moveq, 7000, f100, CF_ISA_A); + INSN(moveq, 7000, f100, M68000); INSN(mvzs, 7100, f100, CF_ISA_B); INSN(or, 8000, f000, CF_ISA_A); + INSN(or, 8000, f000, M68000); INSN(divw, 80c0, f0c0, CF_ISA_A); + INSN(divw, 80c0, f0c0, M68000); INSN(addsub, 9000, f000, CF_ISA_A); + INSN(addsub, 9000, f000, M68000); + INSN(undef, 90c0, f0c0, CF_ISA_A); INSN(subx, 9180, f1f8, CF_ISA_A); + INSN(subx, 9100, f138, M68000); INSN(suba, 91c0, f1c0, CF_ISA_A); + INSN(suba, 90c0, f0c0, M68000); INSN(undef_mac, a000, f000, CF_ISA_A); + INSN(undef_mac, a000, f000, M68000); INSN(mac, a000, f100, CF_EMAC); INSN(from_mac, a180, f9b0, CF_EMAC); INSN(move_mac, a110, f9fc, CF_EMAC); @@ -2856,19 +3848,50 @@ INSN(cmpa, b0c0, f1c0, CF_ISA_B); /* cmpa.w */ INSN(cmp, b080, f1c0, CF_ISA_A); INSN(cmpa, b1c0, f1c0, CF_ISA_A); + INSN(cmp, b000, f100, M68000); + INSN(cmpa, b0c0, f0c0, M68000); INSN(eor, b180, f1c0, CF_ISA_A); + INSN(eor, b180, f1c0, M68000); INSN(and, c000, f000, CF_ISA_A); + INSN(and, c000, f000, M68000); INSN(mulw, c0c0, f0c0, CF_ISA_A); + INSN(mulw, c0c0, f0c0, M68000); INSN(addsub, d000, f000, CF_ISA_A); + INSN(addsub, d000, f000, M68000); + INSN(undef, d0c0, f0c0, CF_ISA_A); INSN(addx, d180, f1f8, CF_ISA_A); + INSN(addx, d100, f138, M68000); INSN(adda, d1c0, f1c0, CF_ISA_A); + INSN(adda, d0c0, f0c0, M68000); INSN(shift_im, e080, f0f0, CF_ISA_A); INSN(shift_reg, e0a0, f0f0, CF_ISA_A); + INSN(shift_im, e080, f0f0, M68000); + INSN(shift8_im, e000, f0f0, M68000); + INSN(shift16_im, e040, f0f0, M68000); + INSN(shift_reg, e0a0, f0f0, M68000); + INSN(shift8_reg, e020, f0f0, M68000); + INSN(shift16_reg, e060, f0f0, M68000); + INSN(rotate_im, e090, f0f0, M68000); + INSN(rotate8_im, e010, f0f0, M68000); + INSN(rotate16_im, e050, f0f0, M68000); + INSN(rotate_reg, e0b0, f0f0, M68000); + INSN(rotate8_reg, e030, f0f0, M68000); + INSN(rotate16_reg,e070, f0f0, M68000); + INSN(shift_mem, e0c0, fcc0, M68000); + INSN(rotate_mem, e4c0, fcc0, M68000); + INSN(bitfield_mem,e8c0, f8c0, M68020_60); + INSN(bitfield_reg,e8c0, f8f8, M68020_60); + INSN(undef_fpu, f000, f000, CF_ISA_A); + INSN(undef_fpu, f000, f000, M68000); INSN(fpu, f200, ffc0, CF_FPU); INSN(fbcc, f280, ffc0, CF_FPU); INSN(frestore, f340, ffc0, CF_FPU); INSN(fsave, f340, ffc0, CF_FPU); + INSN(fpu, f200, ffc0, FPU); + INSN(fbcc, f280, ffc0, FPU); + INSN(frestore, f340, ffc0, FPU); + INSN(fsave, f340, ffc0, FPU); INSN(intouch, f340, ffc0, CF_ISA_A); INSN(cpushl, f428, ff38, CF_ISA_A); INSN(wddata, fb00, ff00, CF_ISA_A);