Signed-off-by: Laurent Vivier <laur...@vivier.eu> --- target/m68k/fpu_helper.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++ target/m68k/helper.h | 1 + target/m68k/translate.c | 59 +++++++++++++-------------- 3 files changed, 133 insertions(+), 30 deletions(-)
diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index 38370d0..3e765d6 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" +#include "exec/cpu_ldst.h" static const floatx80 fpu_rom[128] = { [0x00] = floatx80_pi, /* Pi */ @@ -378,3 +379,105 @@ void HELPER(fconst)(CPUM68KState *env, FPReg *val, uint32_t offset) { val->d = fpu_rom[offset]; } + +static void cpu_ld_floatx80_ra(CPUM68KState *env, FPReg *fp, uint32_t addr, + uintptr_t ra) +{ + uint32_t high; + uint64_t low; + + high = cpu_ldl_data_ra(env, addr, ra); + low = cpu_ldq_data_ra(env, addr + 4, ra); + + fp->l.upper = high >> 16; + fp->l.lower = low; +} + +static void cpu_st_floatx80_ra(CPUM68KState *env, uint32_t addr, FPReg *fp, + uintptr_t ra) +{ + cpu_stl_data_ra(env, addr, fp->l.upper << 16, ra); + cpu_stq_data_ra(env, addr + 4, fp->l.lower, ra); +} + +static void cpu_ld_float64_ra(CPUM68KState *env, FPReg *fp, uint32_t addr, + uintptr_t ra) +{ + uint64_t val; + + val = cpu_ldq_data_ra(env, addr, ra); + fp->d = float64_to_floatx80(*(float64 *)&val, &env->fp_status); +} + +static void cpu_st_float64_ra(CPUM68KState *env, uint32_t addr, FPReg *fp, + uintptr_t ra) +{ + float64 val; + + val = floatx80_to_float64(fp->d, &env->fp_status); + cpu_stq_data_ra(env, addr, *(uint64_t *)&val, ra); +} + +uint32_t HELPER(fmovem)(CPUM68KState *env, uint32_t addr, uint32_t ext) +{ + uintptr_t ra = GETPC(); + int mode = (ext >> 11) & 0x3; + int is_load = ((ext & 0x2000) == 0); + uint16_t mask; + int incr, i; + + if (m68k_feature(env, M68K_FEATURE_FPU)) { + incr = 12; + } else { + incr = 8; + } + + if ((mode & 0x1) == 1) { + /* Dynamic register list */ + int reg = extract32(ext, 4, 3); + mask = env->dregs[reg] & 0x00FF; + } else { + /* Static register list */ + mask = ext & 0x00FF; + } + + if (!is_load && (mode & 2) == 0) { + /* predecrement addressing mode + * only available to store register to memory + */ + for (i = 7; i >= 0; i--, mask <<= 1) { + if (mask & 0x80) { + if (incr == 8) { + cpu_st_float64_ra(env, addr, &env->fregs[i], ra); + } else { + cpu_st_floatx80_ra(env, addr, &env->fregs[i], ra); + } + if ((mask & 0xff) != 0x80) { + addr -= incr; + } + } + } + return addr; + } + /* postincrement addressing mode */ + for (i = 0; i < 8; i++, mask <<= 1) { + if (mask & 0x80) { + if (is_load) { + if (incr == 8) { + cpu_ld_float64_ra(env, &env->fregs[i], addr, ra); + } else { + cpu_ld_floatx80_ra(env, &env->fregs[i], addr, ra); + } + } else { + if (incr == 8) { + cpu_st_float64_ra(env, addr, &env->fregs[i], ra); + } else { + cpu_st_floatx80_ra(env, addr, &env->fregs[i], ra); + } + } + addr += incr; + } + } + + return addr; +} diff --git a/target/m68k/helper.h b/target/m68k/helper.h index b396899..eb3d243 100644 --- a/target/m68k/helper.h +++ b/target/m68k/helper.h @@ -54,6 +54,7 @@ DEF_HELPER_FLAGS_3(fcmp, TCG_CALL_NO_RWG, void, env, fp, fp) DEF_HELPER_FLAGS_2(set_fpcr, TCG_CALL_NO_RWG, void, env, i32) DEF_HELPER_FLAGS_2(ftst, TCG_CALL_NO_RWG, void, env, fp) DEF_HELPER_3(fconst, void, env, fp, i32) +DEF_HELPER_3(fmovem, i32, env, i32, i32) DEF_HELPER_3(mac_move, void, env, i32, i32) DEF_HELPER_3(macmulf, i64, env, i32, i32) diff --git a/target/m68k/translate.c b/target/m68k/translate.c index 3a1bdc1..5061619 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -4505,6 +4505,32 @@ static void gen_op_fmove_fcr(CPUM68KState *env, DisasContext *s, tcg_temp_free_i32(addr); } +static void gen_op_fmovem(CPUM68KState *env, DisasContext *s, + uint32_t insn, uint32_t ext) +{ + int opsize; + TCGv addr, tmp; + + if (m68k_feature(s->env, M68K_FEATURE_FPU)) { + opsize = OS_EXTENDED; + } else { + opsize = OS_DOUBLE; /* FIXME */ + } + + addr = gen_lea(env, s, insn, opsize); + if (IS_NULL_QREG(addr)) { + gen_addr_fault(s); + return; + } + + tmp = tcg_const_i32(ext); + gen_helper_fmovem(tmp, cpu_env, addr, tmp); + if ((insn & 070) == 030 || (insn & 070) == 040) { + tcg_gen_mov_i32(AREG(insn, 0), tmp); + } + tcg_temp_free(tmp); +} + /* ??? FP exceptions are not implemented. Most exceptions are deferred until immediately before the next FP instruction is executed. */ DISAS_INSN(fpu) @@ -4512,7 +4538,6 @@ DISAS_INSN(fpu) uint16_t ext; uint8_t rom_offset; int opmode; - TCGv tmp32; int opsize; TCGv_ptr cpu_src, cpu_dest; @@ -4548,36 +4573,10 @@ DISAS_INSN(fpu) return; case 6: /* fmovem */ case 7: - { - TCGv addr; - TCGv_ptr fp; - uint16_t mask; - int i; - if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0) - goto undef; - tmp32 = gen_lea(env, s, insn, OS_LONG); - if (IS_NULL_QREG(tmp32)) { - gen_addr_fault(s); - return; - } - addr = tcg_temp_new_i32(); - tcg_gen_mov_i32(addr, tmp32); - mask = 0x80; - fp = tcg_temp_new_ptr(); - for (i = 0; i < 8; i++) { - if (ext & mask) { - tcg_gen_addi_ptr(fp, cpu_env, - offsetof(CPUM68KState, fregs[i])); - gen_ldst_fp(s, OS_DOUBLE, addr, fp, - (ext & (1 << 13)) ? EA_STORE : EA_LOADS); - if (ext & (mask - 1)) - tcg_gen_addi_i32(addr, addr, 8); - } - mask >>= 1; - } - tcg_temp_free_i32(addr); - tcg_temp_free_ptr(fp); + if ((ext & 0x1000) == 0 && !m68k_feature(s->env, M68K_FEATURE_FPU)) { + goto undef; } + gen_op_fmovem(env, s, insn, ext); return; } if (ext & (1 << 14)) { -- 2.9.4