mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-04-01 23:07:03 +00:00
target-m68k: use floatx80 internally
Coldfire uses float64, but 680x0 use floatx80. This patch introduces the use of floatx80 internally and enables 680x0 80bits FPU. Backports commit f83311e4764f1f25a8abdec2b32c64483be1759b from qemu
This commit is contained in:
parent
92555a1134
commit
1c6b1e2b9f
|
@ -49,7 +49,7 @@ static void m68k_cpu_reset(CPUState *s)
|
|||
M68kCPU *cpu = M68K_CPU(s->uc, s);
|
||||
M68kCPUClass *mcc = M68K_CPU_GET_CLASS(s->uc, cpu);
|
||||
CPUM68KState *env = &cpu->env;
|
||||
float64 nan = float64_default_nan(NULL);
|
||||
floatx80 nan = floatx80_default_nan(NULL);
|
||||
int i;
|
||||
|
||||
mcc->parent_reset(s);
|
||||
|
@ -60,7 +60,7 @@ static void m68k_cpu_reset(CPUState *s)
|
|||
#endif
|
||||
m68k_switch_sp(env);
|
||||
for (i = 0; i < 8; i++) {
|
||||
env->fregs[i] = nan;
|
||||
env->fregs[i].d = nan;
|
||||
}
|
||||
env->fpcr = 0;
|
||||
env->fpsr = 0;
|
||||
|
|
|
@ -57,8 +57,15 @@
|
|||
#define EXCP_UNINITIALIZED 15
|
||||
#define EXCP_TRAP0 32 /* User trap #0. */
|
||||
#define EXCP_TRAP15 47 /* User trap #15. */
|
||||
#define EXCP_FP_BSUN 48 /* Branch Set on Unordered */
|
||||
#define EXCP_FP_INEX 49 /* Inexact result */
|
||||
#define EXCP_FP_DZ 50 /* Divide by Zero */
|
||||
#define EXCP_FP_UNFL 51 /* Underflow */
|
||||
#define EXCP_FP_OPERR 52 /* Operand Error */
|
||||
#define EXCP_FP_OVFL 53 /* Overflow */
|
||||
#define EXCP_FP_SNAN 54 /* Signaling Not-A-Number */
|
||||
#define EXCP_FP_UNIMP 55 /* Unimplemented Data type */
|
||||
#define EXCP_UNSUPPORTED 61
|
||||
#define EXCP_ICE 13
|
||||
|
||||
#define EXCP_RTE 0x100
|
||||
#define EXCP_HALT_INSN 0x101
|
||||
|
@ -66,6 +73,8 @@
|
|||
#define NB_MMU_MODES 2
|
||||
#define TARGET_INSN_START_EXTRA_WORDS 1
|
||||
|
||||
typedef CPU_LDoubleU FPReg;
|
||||
|
||||
typedef struct CPUM68KState {
|
||||
uint32_t dregs[8];
|
||||
uint32_t aregs[8];
|
||||
|
@ -84,8 +93,8 @@ typedef struct CPUM68KState {
|
|||
uint32_t cc_c; /* either 0/1, unused, or computed from cc_n and cc_v */
|
||||
uint32_t cc_z; /* == 0 or unused */
|
||||
|
||||
float64 fregs[8];
|
||||
float64 fp_result;
|
||||
FPReg fregs[8];
|
||||
FPReg fp_result;
|
||||
uint32_t fpcr;
|
||||
uint32_t fpsr;
|
||||
float_status fp_status;
|
||||
|
|
|
@ -21,92 +21,101 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/exec-all.h"
|
||||
|
||||
uint32_t HELPER(f64_to_i32)(CPUM68KState *env, float64 val)
|
||||
int32_t HELPER(reds32)(CPUM68KState *env, FPReg *val)
|
||||
{
|
||||
return float64_to_int32(val, &env->fp_status);
|
||||
return floatx80_to_int32(val->d, &env->fp_status);
|
||||
}
|
||||
|
||||
float32 HELPER(f64_to_f32)(CPUM68KState *env, float64 val)
|
||||
float32 HELPER(redf32)(CPUM68KState *env, FPReg *val)
|
||||
{
|
||||
return float64_to_float32(val, &env->fp_status);
|
||||
return floatx80_to_float32(val->d, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(i32_to_f64)(CPUM68KState *env, uint32_t val)
|
||||
void HELPER(exts32)(CPUM68KState *env, FPReg *res, int32_t val)
|
||||
{
|
||||
return int32_to_float64(val, &env->fp_status);
|
||||
res->d = int32_to_floatx80(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(f32_to_f64)(CPUM68KState *env, float32 val)
|
||||
void HELPER(extf32)(CPUM68KState *env, FPReg *res, float32 val)
|
||||
{
|
||||
return float32_to_float64(val, &env->fp_status);
|
||||
res->d = float32_to_floatx80(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(iround_f64)(CPUM68KState *env, float64 val)
|
||||
void HELPER(extf64)(CPUM68KState *env, FPReg *res, float64 val)
|
||||
{
|
||||
return float64_round_to_int(val, &env->fp_status);
|
||||
res->d = float64_to_floatx80(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(itrunc_f64)(CPUM68KState *env, float64 val)
|
||||
float64 HELPER(redf64)(CPUM68KState *env, FPReg *val)
|
||||
{
|
||||
return float64_trunc_to_int(val, &env->fp_status);
|
||||
return floatx80_to_float64(val->d, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(sqrt_f64)(CPUM68KState *env, float64 val)
|
||||
void HELPER(firound)(CPUM68KState *env, FPReg *res, FPReg *val)
|
||||
{
|
||||
return float64_sqrt(val, &env->fp_status);
|
||||
res->d = floatx80_round_to_int(val->d, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(abs_f64)(float64 val)
|
||||
void HELPER(fitrunc)(CPUM68KState *env, FPReg *res, FPReg *val)
|
||||
{
|
||||
return float64_abs(val);
|
||||
res->d = floatx80_round_to_int(val->d, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(chs_f64)(float64 val)
|
||||
void HELPER(fsqrt)(CPUM68KState *env, FPReg *res, FPReg *val)
|
||||
{
|
||||
return float64_chs(val);
|
||||
res->d = floatx80_sqrt(val->d, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(add_f64)(CPUM68KState *env, float64 a, float64 b)
|
||||
void HELPER(fabs)(CPUM68KState *env, FPReg *res, FPReg *val)
|
||||
{
|
||||
return float64_add(a, b, &env->fp_status);
|
||||
res->d = floatx80_abs(val->d);
|
||||
}
|
||||
|
||||
float64 HELPER(sub_f64)(CPUM68KState *env, float64 a, float64 b)
|
||||
void HELPER(fchs)(CPUM68KState *env, FPReg *res, FPReg *val)
|
||||
{
|
||||
return float64_sub(a, b, &env->fp_status);
|
||||
res->d = floatx80_chs(val->d);
|
||||
}
|
||||
|
||||
float64 HELPER(mul_f64)(CPUM68KState *env, float64 a, float64 b)
|
||||
void HELPER(fadd)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
|
||||
{
|
||||
return float64_mul(a, b, &env->fp_status);
|
||||
res->d = floatx80_add(val0->d, val1->d, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(div_f64)(CPUM68KState *env, float64 a, float64 b)
|
||||
void HELPER(fsub)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
|
||||
{
|
||||
return float64_div(a, b, &env->fp_status);
|
||||
res->d = floatx80_sub(val1->d, val0->d, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(sub_cmp_f64)(CPUM68KState *env, float64 a, float64 b)
|
||||
void HELPER(fmul)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
|
||||
{
|
||||
res->d = floatx80_mul(val0->d, val1->d, &env->fp_status);
|
||||
}
|
||||
|
||||
void HELPER(fdiv)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
|
||||
{
|
||||
res->d = floatx80_div(val1->d, val0->d, &env->fp_status);
|
||||
}
|
||||
|
||||
void HELPER(fsub_cmp)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
|
||||
{
|
||||
/* ??? This may incorrectly raise exceptions. */
|
||||
/* ??? Should flush denormals to zero. */
|
||||
float64 res;
|
||||
res = float64_sub(a, b, &env->fp_status);
|
||||
if (float64_is_quiet_nan(res, &env->fp_status)) {
|
||||
res->d = floatx80_sub(val0->d, val1->d, &env->fp_status);
|
||||
if (floatx80_is_quiet_nan(res->d, &env->fp_status)) {
|
||||
/* +/-inf compares equal against itself, but sub returns nan. */
|
||||
if (!float64_is_quiet_nan(a, &env->fp_status)
|
||||
&& !float64_is_quiet_nan(b, &env->fp_status)) {
|
||||
res = float64_zero;
|
||||
if (float64_lt_quiet(a, res, &env->fp_status)) {
|
||||
res = float64_chs(res);
|
||||
if (!floatx80_is_quiet_nan(val0->d, &env->fp_status)
|
||||
&& !floatx80_is_quiet_nan(val1->d, &env->fp_status)) {
|
||||
res->d = floatx80_zero;
|
||||
if (floatx80_lt_quiet(val0->d, res->d, &env->fp_status)) {
|
||||
res->d = floatx80_chs(res->d);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t HELPER(compare_f64)(CPUM68KState *env, float64 val)
|
||||
uint32_t HELPER(fcompare)(CPUM68KState *env, FPReg *val)
|
||||
{
|
||||
return float64_compare_quiet(val, float64_zero, &env->fp_status);
|
||||
return floatx80_compare_quiet(val->d, floatx80_zero, &env->fp_status);
|
||||
}
|
||||
|
|
|
@ -14,21 +14,28 @@ DEF_HELPER_3(movec, void, env, i32, i32)
|
|||
DEF_HELPER_4(cas2w, void, env, i32, i32, i32)
|
||||
DEF_HELPER_4(cas2l, void, env, i32, i32, i32)
|
||||
|
||||
DEF_HELPER_2(f64_to_i32, f32, env, f64)
|
||||
DEF_HELPER_2(f64_to_f32, f32, env, f64)
|
||||
DEF_HELPER_2(i32_to_f64, f64, env, i32)
|
||||
DEF_HELPER_2(f32_to_f64, f64, env, f32)
|
||||
DEF_HELPER_2(iround_f64, f64, env, f64)
|
||||
DEF_HELPER_2(itrunc_f64, f64, env, f64)
|
||||
DEF_HELPER_2(sqrt_f64, f64, env, f64)
|
||||
DEF_HELPER_1(abs_f64, f64, f64)
|
||||
DEF_HELPER_1(chs_f64, f64, f64)
|
||||
DEF_HELPER_3(add_f64, f64, env, f64, f64)
|
||||
DEF_HELPER_3(sub_f64, f64, env, f64, f64)
|
||||
DEF_HELPER_3(mul_f64, f64, env, f64, f64)
|
||||
DEF_HELPER_3(div_f64, f64, env, f64, f64)
|
||||
DEF_HELPER_3(sub_cmp_f64, f64, env, f64, f64)
|
||||
DEF_HELPER_2(compare_f64, i32, env, f64)
|
||||
#define dh_alias_fp ptr
|
||||
#define dh_ctype_fp FPReg *
|
||||
#define dh_is_signed_fp dh_is_signed_ptr
|
||||
|
||||
DEF_HELPER_3(exts32, void, env, fp, s32)
|
||||
DEF_HELPER_3(extf32, void, env, fp, f32)
|
||||
DEF_HELPER_3(extf64, void, env, fp, f64)
|
||||
DEF_HELPER_2(redf32, f32, env, fp)
|
||||
DEF_HELPER_2(redf64, f64, env, fp)
|
||||
DEF_HELPER_2(reds32, s32, env, fp)
|
||||
|
||||
DEF_HELPER_3(firound, void, env, fp, fp)
|
||||
DEF_HELPER_3(fitrunc, void, env, fp, fp)
|
||||
DEF_HELPER_3(fsqrt, void, env, fp, fp)
|
||||
DEF_HELPER_3(fabs, void, env, fp, fp)
|
||||
DEF_HELPER_3(fchs, void, env, fp, fp)
|
||||
DEF_HELPER_4(fadd, void, env, fp, fp, fp)
|
||||
DEF_HELPER_4(fsub, void, env, fp, fp, fp)
|
||||
DEF_HELPER_4(fmul, void, env, fp, fp, fp)
|
||||
DEF_HELPER_4(fdiv, void, env, fp, fp, fp)
|
||||
DEF_HELPER_4(fsub_cmp, void, env, fp, fp, fp)
|
||||
DEF_HELPER_2(fcompare, i32, env, fp)
|
||||
|
||||
DEF_HELPER_3(mac_move, void, env, i32, i32)
|
||||
DEF_HELPER_3(macmulf, i64, env, i32, i32)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
DEFF64(FP_RESULT, fp_result)
|
||||
DEFO32(PC, pc)
|
||||
DEFO32(SR, sr)
|
||||
DEFO32(CC_OP, cc_op)
|
||||
|
|
|
@ -32,15 +32,9 @@
|
|||
|
||||
//#define DEBUG_DISPATCH 1
|
||||
|
||||
/* Fake floating point. */
|
||||
#define tcg_gen_mov_f64 tcg_gen_mov_i64
|
||||
#define tcg_gen_qemu_ldf64 tcg_gen_qemu_ld64
|
||||
#define tcg_gen_qemu_stf64 tcg_gen_qemu_st64
|
||||
|
||||
#define REG(insn, pos) (((insn) >> (pos)) & 7)
|
||||
#define DREG(insn, pos) tcg_ctx->cpu_dregs[REG(insn, pos)]
|
||||
#define AREG(insn, pos) get_areg(s, REG(insn, pos))
|
||||
#define FREG(insn, pos) tcg_ctx->cpu_fregs[REG(insn, pos)]
|
||||
#define MACREG(acc) tcg_ctx->cpu_macc[acc]
|
||||
#define QREG_SP tcg_ctx->cpu_aregs[7]
|
||||
|
||||
|
@ -57,11 +51,9 @@ void m68k_tcg_init(struct uc_struct *uc)
|
|||
|
||||
#define DEFO32(name, offset) tcg_ctx->QREG_##name = tcg_global_mem_new_i32(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPUM68KState, offset), #name);
|
||||
#define DEFO64(name, offset) tcg_ctx->QREG_##name = tcg_global_mem_new_i64(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPUM68KState, offset), #name);
|
||||
#define DEFF64(name, offset) DEFO64(name, offset)
|
||||
#include "qregs.def"
|
||||
#undef DEFO32
|
||||
#undef DEFO64
|
||||
#undef DEFF64
|
||||
|
||||
// tcg_ctx->QREG_FP_RESULT = tcg_global_mem_new_i64(tcg_ctx, tcg_ctx->cpu_env, offsetof(CPUM68KState, fp_result), "FP_RESULT");
|
||||
|
||||
|
@ -80,10 +72,6 @@ void m68k_tcg_init(struct uc_struct *uc)
|
|||
tcg_ctx->cpu_aregs[i] = tcg_global_mem_new(tcg_ctx, tcg_ctx->cpu_env,
|
||||
offsetof(CPUM68KState, aregs[i]), p);
|
||||
p += 3;
|
||||
sprintf(p, "F%d", i);
|
||||
tcg_ctx->cpu_fregs[i] = tcg_global_mem_new_i64(tcg_ctx, tcg_ctx->cpu_env,
|
||||
offsetof(CPUM68KState, fregs[i]), p);
|
||||
p += 3;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
|
@ -250,6 +238,47 @@ static void update_cc_op(DisasContext *s)
|
|||
}
|
||||
}
|
||||
|
||||
/* Generate a jump to an immediate address. */
|
||||
static void gen_jmp_im(DisasContext *s, uint32_t dest)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
|
||||
update_cc_op(s);
|
||||
tcg_gen_movi_i32(tcg_ctx, tcg_ctx->QREG_PC, dest);
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
}
|
||||
|
||||
/* Generate a jump to the address in qreg DEST. */
|
||||
static void gen_jmp(DisasContext *s, TCGv dest)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
|
||||
update_cc_op(s);
|
||||
tcg_gen_mov_i32(tcg_ctx, tcg_ctx->QREG_PC, dest);
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
}
|
||||
|
||||
static void gen_raise_exception(DisasContext *s, int nr)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv_i32 tmp = tcg_const_i32(tcg_ctx, nr);
|
||||
|
||||
gen_helper_raise_exception(tcg_ctx, tcg_ctx->cpu_env, tmp);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp);
|
||||
}
|
||||
|
||||
static void gen_exception(DisasContext *s, uint32_t where, int nr)
|
||||
{
|
||||
update_cc_op(s);
|
||||
gen_jmp_im(s, where);
|
||||
gen_raise_exception(s, nr);
|
||||
}
|
||||
|
||||
static inline void gen_addr_fault(DisasContext *s)
|
||||
{
|
||||
gen_exception(s, s->insn_pc, EXCP_ADDRESS);
|
||||
}
|
||||
|
||||
/* Generate a load from the specified address. Narrow values are
|
||||
sign extended to full register width. */
|
||||
static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign)
|
||||
|
@ -272,7 +301,6 @@ static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign)
|
|||
tcg_gen_qemu_ld16u(s->uc, tmp, addr, index);
|
||||
break;
|
||||
case OS_LONG:
|
||||
case OS_SINGLE:
|
||||
tcg_gen_qemu_ld32u(s->uc, tmp, addr, index);
|
||||
break;
|
||||
default:
|
||||
|
@ -281,16 +309,6 @@ static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign)
|
|||
return tmp;
|
||||
}
|
||||
|
||||
static inline TCGv_i64 gen_load64(DisasContext * s, TCGv addr)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv_i64 tmp;
|
||||
int index = IS_USER(s);
|
||||
tmp = tcg_temp_new_i64(tcg_ctx);
|
||||
tcg_gen_qemu_ldf64(s->uc, tmp, addr, index);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* Generate a store. */
|
||||
static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val)
|
||||
{
|
||||
|
@ -303,7 +321,6 @@ static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val)
|
|||
tcg_gen_qemu_st16(s->uc, val, addr, index);
|
||||
break;
|
||||
case OS_LONG:
|
||||
case OS_SINGLE:
|
||||
tcg_gen_qemu_st32(s->uc, val, addr, index);
|
||||
break;
|
||||
default:
|
||||
|
@ -311,12 +328,6 @@ static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void gen_store64(DisasContext *s, TCGv addr, TCGv_i64 val)
|
||||
{
|
||||
int index = IS_USER(s);
|
||||
tcg_gen_qemu_stf64(s->uc, val, addr, index);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
EA_STORE,
|
||||
EA_LOADU,
|
||||
|
@ -362,6 +373,15 @@ static inline uint32_t read_im32(CPUM68KState *env, DisasContext *s)
|
|||
return im;
|
||||
}
|
||||
|
||||
/* Read a 64-bit immediate constant. */
|
||||
static inline uint64_t read_im64(CPUM68KState *env, DisasContext *s)
|
||||
{
|
||||
uint64_t im;
|
||||
im = (uint64_t)read_im32(env, s) << 32;
|
||||
im |= (uint64_t)read_im32(env, s);
|
||||
return im;
|
||||
}
|
||||
|
||||
/* Calculate and address index. */
|
||||
static TCGv gen_addr_index(DisasContext *s, uint16_t ext, TCGv tmp)
|
||||
{
|
||||
|
@ -910,6 +930,310 @@ static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn,
|
|||
return gen_ea_mode(env, s, mode, reg0, opsize, val, addrp, what);
|
||||
}
|
||||
|
||||
static TCGv_ptr gen_fp_ptr(DisasContext *s, int freg)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv_ptr fp = tcg_temp_new_ptr(tcg_ctx);
|
||||
|
||||
tcg_gen_addi_ptr(tcg_ctx, fp, tcg_ctx->cpu_env, offsetof(CPUM68KState, fregs[freg]));
|
||||
return fp;
|
||||
}
|
||||
|
||||
static TCGv_ptr gen_fp_result_ptr(DisasContext *s)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv_ptr fp = tcg_temp_new_ptr(tcg_ctx);
|
||||
|
||||
tcg_gen_addi_ptr(tcg_ctx, fp, tcg_ctx->cpu_env, offsetof(CPUM68KState, fp_result));
|
||||
return fp;
|
||||
}
|
||||
|
||||
static void gen_fp_move(DisasContext *s, TCGv_ptr dest, TCGv_ptr src)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv t32;
|
||||
TCGv_i64 t64;
|
||||
|
||||
t32 = tcg_temp_new(tcg_ctx);
|
||||
tcg_gen_ld16u_i32(tcg_ctx, t32, src, offsetof(FPReg, l.upper));
|
||||
tcg_gen_st16_i32(tcg_ctx, t32, dest, offsetof(FPReg, l.upper));
|
||||
tcg_temp_free(tcg_ctx, t32);
|
||||
|
||||
t64 = tcg_temp_new_i64(tcg_ctx);
|
||||
tcg_gen_ld_i64(tcg_ctx, t64, src, offsetof(FPReg, l.lower));
|
||||
tcg_gen_st_i64(tcg_ctx, t64, dest, offsetof(FPReg, l.lower));
|
||||
tcg_temp_free_i64(tcg_ctx, t64);
|
||||
}
|
||||
|
||||
static void gen_load_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv tmp;
|
||||
TCGv_i64 t64;
|
||||
int index = IS_USER(s);
|
||||
|
||||
t64 = tcg_temp_new_i64(tcg_ctx);
|
||||
tmp = tcg_temp_new(tcg_ctx);
|
||||
switch (opsize) {
|
||||
case OS_BYTE:
|
||||
tcg_gen_qemu_ld8s(s->uc, tmp, addr, index);
|
||||
gen_helper_exts32(tcg_ctx, tcg_ctx->cpu_env, fp, tmp);
|
||||
break;
|
||||
case OS_WORD:
|
||||
tcg_gen_qemu_ld16s(s->uc, tmp, addr, index);
|
||||
gen_helper_exts32(tcg_ctx, tcg_ctx->cpu_env, fp, tmp);
|
||||
break;
|
||||
case OS_LONG:
|
||||
tcg_gen_qemu_ld32u(s->uc, tmp, addr, index);
|
||||
gen_helper_exts32(tcg_ctx, tcg_ctx->cpu_env, fp, tmp);
|
||||
break;
|
||||
case OS_SINGLE:
|
||||
tcg_gen_qemu_ld32u(s->uc, tmp, addr, index);
|
||||
gen_helper_extf32(tcg_ctx, tcg_ctx->cpu_env, fp, tmp);
|
||||
break;
|
||||
case OS_DOUBLE:
|
||||
tcg_gen_qemu_ld64(s->uc, t64, addr, index);
|
||||
gen_helper_extf64(tcg_ctx, tcg_ctx->cpu_env, fp, t64);
|
||||
tcg_temp_free_i64(tcg_ctx, t64);
|
||||
break;
|
||||
case OS_EXTENDED:
|
||||
if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
|
||||
gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
|
||||
break;
|
||||
}
|
||||
tcg_gen_qemu_ld32u(s->uc, tmp, addr, index);
|
||||
tcg_gen_shri_i32(tcg_ctx, tmp, tmp, 16);
|
||||
tcg_gen_st16_i32(tcg_ctx, tmp, fp, offsetof(FPReg, l.upper));
|
||||
tcg_gen_addi_i32(tcg_ctx, tmp, addr, 4);
|
||||
tcg_gen_qemu_ld64(s->uc, t64, tmp, index);
|
||||
tcg_gen_st_i64(tcg_ctx, t64, fp, offsetof(FPReg, l.lower));
|
||||
break;
|
||||
case OS_PACKED:
|
||||
/* unimplemented data type on 68040/ColdFire
|
||||
* FIXME if needed for another FPU
|
||||
*/
|
||||
gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
tcg_temp_free(tcg_ctx, tmp);
|
||||
tcg_temp_free_i64(tcg_ctx, t64);
|
||||
}
|
||||
|
||||
static void gen_store_fp(DisasContext *s, int opsize, TCGv addr, TCGv_ptr fp)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv tmp;
|
||||
TCGv_i64 t64;
|
||||
int index = IS_USER(s);
|
||||
|
||||
t64 = tcg_temp_new_i64(tcg_ctx);
|
||||
tmp = tcg_temp_new(tcg_ctx);
|
||||
switch (opsize) {
|
||||
case OS_BYTE:
|
||||
gen_helper_reds32(tcg_ctx, tmp, tcg_ctx->cpu_env, fp);
|
||||
tcg_gen_qemu_st8(s->uc, tmp, addr, index);
|
||||
break;
|
||||
case OS_WORD:
|
||||
gen_helper_reds32(tcg_ctx, tmp, tcg_ctx->cpu_env, fp);
|
||||
tcg_gen_qemu_st16(s->uc, tmp, addr, index);
|
||||
break;
|
||||
case OS_LONG:
|
||||
gen_helper_reds32(tcg_ctx, tmp, tcg_ctx->cpu_env, fp);
|
||||
tcg_gen_qemu_st32(s->uc, tmp, addr, index);
|
||||
break;
|
||||
case OS_SINGLE:
|
||||
gen_helper_redf32(tcg_ctx, tmp, tcg_ctx->cpu_env, fp);
|
||||
tcg_gen_qemu_st32(s->uc, tmp, addr, index);
|
||||
break;
|
||||
case OS_DOUBLE:
|
||||
gen_helper_redf64(tcg_ctx, t64, tcg_ctx->cpu_env, fp);
|
||||
tcg_gen_qemu_st64(s->uc, t64, addr, index);
|
||||
break;
|
||||
case OS_EXTENDED:
|
||||
if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
|
||||
gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
|
||||
break;
|
||||
}
|
||||
tcg_gen_ld16u_i32(tcg_ctx, tmp, fp, offsetof(FPReg, l.upper));
|
||||
tcg_gen_shli_i32(tcg_ctx, tmp, tmp, 16);
|
||||
tcg_gen_qemu_st32(s->uc, tmp, addr, index);
|
||||
tcg_gen_addi_i32(tcg_ctx, tmp, addr, 4);
|
||||
tcg_gen_ld_i64(tcg_ctx, t64, fp, offsetof(FPReg, l.lower));
|
||||
tcg_gen_qemu_st64(s->uc, t64, tmp, index);
|
||||
break;
|
||||
case OS_PACKED:
|
||||
/* unimplemented data type on 68040/ColdFire
|
||||
* FIXME if needed for another FPU
|
||||
*/
|
||||
gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
tcg_temp_free(tcg_ctx, tmp);
|
||||
tcg_temp_free_i64(tcg_ctx, t64);
|
||||
}
|
||||
|
||||
static void gen_ldst_fp(DisasContext *s, int opsize, TCGv addr,
|
||||
TCGv_ptr fp, ea_what what)
|
||||
{
|
||||
if (what == EA_STORE) {
|
||||
gen_store_fp(s, opsize, addr, fp);
|
||||
} else {
|
||||
gen_load_fp(s, opsize, addr, fp);
|
||||
}
|
||||
}
|
||||
|
||||
static int gen_ea_mode_fp(CPUM68KState *env, DisasContext *s, int mode,
|
||||
int reg0, int opsize, TCGv_ptr fp, ea_what what)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv reg, addr, tmp;
|
||||
TCGv_i64 t64;
|
||||
|
||||
switch (mode) {
|
||||
case 0: /* Data register direct. */
|
||||
reg = tcg_ctx->cpu_dregs[reg0];
|
||||
if (what == EA_STORE) {
|
||||
switch (opsize) {
|
||||
case OS_BYTE:
|
||||
case OS_WORD:
|
||||
case OS_LONG:
|
||||
gen_helper_reds32(tcg_ctx, reg, tcg_ctx->cpu_env, fp);
|
||||
break;
|
||||
case OS_SINGLE:
|
||||
gen_helper_redf32(tcg_ctx, reg, tcg_ctx->cpu_env, fp);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
} else {
|
||||
tmp = tcg_temp_new(tcg_ctx);
|
||||
switch (opsize) {
|
||||
case OS_BYTE:
|
||||
tcg_gen_ext8s_i32(tcg_ctx, tmp, reg);
|
||||
gen_helper_exts32(tcg_ctx, tcg_ctx->cpu_env, fp, tmp);
|
||||
break;
|
||||
case OS_WORD:
|
||||
tcg_gen_ext16s_i32(tcg_ctx, tmp, reg);
|
||||
gen_helper_exts32(tcg_ctx, tcg_ctx->cpu_env, fp, tmp);
|
||||
break;
|
||||
case OS_LONG:
|
||||
gen_helper_exts32(tcg_ctx, tcg_ctx->cpu_env, fp, reg);
|
||||
break;
|
||||
case OS_SINGLE:
|
||||
gen_helper_extf32(tcg_ctx, tcg_ctx->cpu_env, fp, reg);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
tcg_temp_free(tcg_ctx, tmp);
|
||||
}
|
||||
return 0;
|
||||
case 1: /* Address register direct. */
|
||||
return -1;
|
||||
case 2: /* Indirect register */
|
||||
addr = get_areg(s, reg0);
|
||||
gen_ldst_fp(s, opsize, addr, fp, what);
|
||||
return 0;
|
||||
case 3: /* Indirect postincrement. */
|
||||
addr = tcg_ctx->cpu_aregs[reg0];
|
||||
gen_ldst_fp(s, opsize, addr, fp, what);
|
||||
tcg_gen_addi_i32(tcg_ctx, addr, addr, opsize_bytes(opsize));
|
||||
return 0;
|
||||
case 4: /* Indirect predecrememnt. */
|
||||
addr = gen_lea_mode(env, s, mode, reg0, opsize);
|
||||
if (IS_NULL_QREG(addr)) {
|
||||
return -1;
|
||||
}
|
||||
gen_ldst_fp(s, opsize, addr, fp, what);
|
||||
tcg_gen_mov_i32(tcg_ctx, tcg_ctx->cpu_aregs[reg0], addr);
|
||||
return 0;
|
||||
case 5: /* Indirect displacement. */
|
||||
case 6: /* Indirect index + displacement. */
|
||||
do_indirect:
|
||||
addr = gen_lea_mode(env, s, mode, reg0, opsize);
|
||||
if (IS_NULL_QREG(addr)) {
|
||||
return -1;
|
||||
}
|
||||
gen_ldst_fp(s, opsize, addr, fp, what);
|
||||
return 0;
|
||||
case 7: /* Other */
|
||||
switch (reg0) {
|
||||
case 0: /* Absolute short. */
|
||||
case 1: /* Absolute long. */
|
||||
case 2: /* pc displacement */
|
||||
case 3: /* pc index+displacement. */
|
||||
goto do_indirect;
|
||||
case 4: /* Immediate. */
|
||||
if (what == EA_STORE) {
|
||||
return -1;
|
||||
}
|
||||
switch (opsize) {
|
||||
case OS_BYTE:
|
||||
tmp = tcg_const_i32(tcg_ctx, (int8_t)read_im8(env, s));
|
||||
gen_helper_exts32(tcg_ctx, tcg_ctx->cpu_env, fp, tmp);
|
||||
tcg_temp_free(tcg_ctx, tmp);
|
||||
break;
|
||||
case OS_WORD:
|
||||
tmp = tcg_const_i32(tcg_ctx, (int16_t)read_im16(env, s));
|
||||
gen_helper_exts32(tcg_ctx, tcg_ctx->cpu_env, fp, tmp);
|
||||
tcg_temp_free(tcg_ctx, tmp);
|
||||
break;
|
||||
case OS_LONG:
|
||||
tmp = tcg_const_i32(tcg_ctx, read_im32(env, s));
|
||||
gen_helper_exts32(tcg_ctx, tcg_ctx->cpu_env, fp, tmp);
|
||||
tcg_temp_free(tcg_ctx, tmp);
|
||||
break;
|
||||
case OS_SINGLE:
|
||||
tmp = tcg_const_i32(tcg_ctx, read_im32(env, s));
|
||||
gen_helper_extf32(tcg_ctx, tcg_ctx->cpu_env, fp, tmp);
|
||||
tcg_temp_free(tcg_ctx, tmp);
|
||||
break;
|
||||
case OS_DOUBLE:
|
||||
t64 = tcg_const_i64(tcg_ctx, read_im64(env, s));
|
||||
gen_helper_extf64(tcg_ctx, tcg_ctx->cpu_env, fp, t64);
|
||||
tcg_temp_free_i64(tcg_ctx, t64);
|
||||
break;
|
||||
case OS_EXTENDED:
|
||||
if (m68k_feature(s->env, M68K_FEATURE_CF_FPU)) {
|
||||
gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
|
||||
break;
|
||||
}
|
||||
tmp = tcg_const_i32(tcg_ctx, read_im32(env, s) >> 16);
|
||||
tcg_gen_st16_i32(tcg_ctx, tmp, fp, offsetof(FPReg, l.upper));
|
||||
tcg_temp_free(tcg_ctx, tmp);
|
||||
t64 = tcg_const_i64(tcg_ctx, read_im64(env, s));
|
||||
tcg_gen_st_i64(tcg_ctx, t64, fp, offsetof(FPReg, l.lower));
|
||||
tcg_temp_free_i64(tcg_ctx, t64);
|
||||
break;
|
||||
case OS_PACKED:
|
||||
/* unimplemented data type on 68040/ColdFire
|
||||
* FIXME if needed for another FPU
|
||||
*/
|
||||
gen_exception(s, s->insn_pc, EXCP_FP_UNIMP);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int gen_ea_fp(CPUM68KState *env, DisasContext *s, uint16_t insn,
|
||||
int opsize, TCGv_ptr fp, ea_what what)
|
||||
{
|
||||
int mode = extract32(insn, 3, 3);
|
||||
int reg0 = REG(insn, 0);
|
||||
return gen_ea_mode_fp(env, s, mode, reg0, opsize, fp, what);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
TCGCond tcond;
|
||||
bool g1;
|
||||
|
@ -1132,45 +1456,6 @@ static void gen_lookup_tb(DisasContext *s)
|
|||
s->is_jmp = DISAS_UPDATE;
|
||||
}
|
||||
|
||||
/* Generate a jump to an immediate address. */
|
||||
static void gen_jmp_im(DisasContext *s, uint32_t dest)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
update_cc_op(s);
|
||||
tcg_gen_movi_i32(tcg_ctx, tcg_ctx->QREG_PC, dest);
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
}
|
||||
|
||||
/* Generate a jump to the address in qreg DEST. */
|
||||
static void gen_jmp(DisasContext *s, TCGv dest)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
update_cc_op(s);
|
||||
tcg_gen_mov_i32(tcg_ctx, tcg_ctx->QREG_PC, dest);
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
}
|
||||
|
||||
static void gen_raise_exception(DisasContext *s, int nr)
|
||||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
TCGv_i32 tmp = tcg_const_i32(tcg_ctx, nr);
|
||||
|
||||
gen_helper_raise_exception(tcg_ctx, tcg_ctx->cpu_env, tmp);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp);
|
||||
}
|
||||
|
||||
static void gen_exception(DisasContext *s, uint32_t where, int nr)
|
||||
{
|
||||
update_cc_op(s);
|
||||
gen_jmp_im(s, where);
|
||||
gen_raise_exception(s, nr);
|
||||
}
|
||||
|
||||
static inline void gen_addr_fault(DisasContext *s)
|
||||
{
|
||||
gen_exception(s, s->insn_pc, EXCP_ADDRESS);
|
||||
}
|
||||
|
||||
#define SRC_EA(env, result, opsize, op_sign, addrp) do { \
|
||||
result = gen_ea(env, s, insn, opsize, tcg_ctx->NULL_QREG, addrp, \
|
||||
op_sign ? EA_LOADS : EA_LOADU); \
|
||||
|
@ -4292,15 +4577,11 @@ DISAS_INSN(fpu)
|
|||
{
|
||||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
uint16_t ext;
|
||||
int32_t offset;
|
||||
int opmode;
|
||||
TCGv_i64 src;
|
||||
TCGv_i64 dest;
|
||||
TCGv_i64 res;
|
||||
TCGv tmp32;
|
||||
int round;
|
||||
int set_dest;
|
||||
int opsize;
|
||||
TCGv_ptr cpu_src, cpu_dest;
|
||||
|
||||
ext = read_im16(env, s);
|
||||
opmode = ext & 0x7f;
|
||||
|
@ -4310,58 +4591,12 @@ DISAS_INSN(fpu)
|
|||
case 1:
|
||||
goto undef;
|
||||
case 3: /* fmove out */
|
||||
src = FREG(ext, 7);
|
||||
tmp32 = tcg_temp_new_i32(tcg_ctx);
|
||||
/* fmove */
|
||||
/* ??? TODO: Proper behavior on overflow. */
|
||||
cpu_src = gen_fp_ptr(s, REG(ext, 7));
|
||||
opsize = ext_opsize(ext, 10);
|
||||
switch (opsize) {
|
||||
case OS_LONG:
|
||||
gen_helper_f64_to_i32(tcg_ctx, tmp32, tcg_ctx->cpu_env, src);
|
||||
break;
|
||||
case OS_SINGLE:
|
||||
gen_helper_f64_to_f32(tcg_ctx, tmp32, tcg_ctx->cpu_env, src);
|
||||
break;
|
||||
case OS_WORD:
|
||||
gen_helper_f64_to_i32(tcg_ctx, tmp32, tcg_ctx->cpu_env, src);
|
||||
break;
|
||||
case OS_DOUBLE:
|
||||
tcg_gen_mov_i32(tcg_ctx, tmp32, AREG(insn, 0));
|
||||
switch ((insn >> 3) & 7) {
|
||||
case 2:
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
tcg_gen_addi_i32(tcg_ctx, tmp32, tmp32, -8);
|
||||
break;
|
||||
case 5:
|
||||
offset = cpu_ldsw_code(env, s->pc);
|
||||
s->pc += 2;
|
||||
tcg_gen_addi_i32(tcg_ctx, tmp32, tmp32, offset);
|
||||
break;
|
||||
default:
|
||||
goto undef;
|
||||
}
|
||||
gen_store64(s, tmp32, src);
|
||||
switch ((insn >> 3) & 7) {
|
||||
case 3:
|
||||
tcg_gen_addi_i32(tcg_ctx, tmp32, tmp32, 8);
|
||||
tcg_gen_mov_i32(tcg_ctx, AREG(insn, 0), tmp32);
|
||||
break;
|
||||
case 4:
|
||||
tcg_gen_mov_i32(tcg_ctx, AREG(insn, 0), tmp32);
|
||||
break;
|
||||
}
|
||||
tcg_temp_free_i32(tcg_ctx, tmp32);
|
||||
return;
|
||||
case OS_BYTE:
|
||||
gen_helper_f64_to_i32(tcg_ctx, tmp32, tcg_ctx->cpu_env, src);
|
||||
break;
|
||||
default:
|
||||
goto undef;
|
||||
if (gen_ea_fp(env, s, insn, opsize, cpu_src, EA_STORE) == -1) {
|
||||
gen_addr_fault(s);
|
||||
}
|
||||
DEST_EA(env, insn, opsize, tmp32, NULL);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp32);
|
||||
tcg_temp_free_ptr(tcg_ctx, cpu_src);
|
||||
return;
|
||||
case 4: /* fmove to control register. */
|
||||
case 5: /* fmove from control register. */
|
||||
|
@ -4371,6 +4606,7 @@ DISAS_INSN(fpu)
|
|||
case 7:
|
||||
{
|
||||
TCGv addr;
|
||||
TCGv_ptr fp;
|
||||
uint16_t mask;
|
||||
int i;
|
||||
if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0)
|
||||
|
@ -4383,136 +4619,86 @@ DISAS_INSN(fpu)
|
|||
addr = tcg_temp_new_i32(tcg_ctx);
|
||||
tcg_gen_mov_i32(tcg_ctx, addr, tmp32);
|
||||
mask = 0x80;
|
||||
fp = tcg_temp_new_ptr(tcg_ctx);
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (ext & mask) {
|
||||
dest = FREG(i, 0);
|
||||
if (ext & (1 << 13)) {
|
||||
/* store */
|
||||
tcg_gen_qemu_stf64(s->uc, dest, addr, IS_USER(s));
|
||||
} else {
|
||||
/* load */
|
||||
tcg_gen_qemu_ldf64(s->uc, dest, addr, IS_USER(s));
|
||||
}
|
||||
tcg_gen_addi_ptr(tcg_ctx, fp, tcg_ctx->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(tcg_ctx, addr, addr, 8);
|
||||
}
|
||||
mask >>= 1;
|
||||
}
|
||||
tcg_temp_free_i32(tcg_ctx, addr);
|
||||
tcg_temp_free_ptr(tcg_ctx, fp);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (ext & (1 << 14)) {
|
||||
/* Source effective address. */
|
||||
opsize = ext_opsize(ext, 10);
|
||||
if (opsize == OS_DOUBLE) {
|
||||
tmp32 = tcg_temp_new_i32(tcg_ctx);
|
||||
tcg_gen_mov_i32(tcg_ctx, tmp32, AREG(insn, 0));
|
||||
switch ((insn >> 3) & 7) {
|
||||
case 2:
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
tcg_gen_addi_i32(tcg_ctx, tmp32, tmp32, -8);
|
||||
break;
|
||||
case 5:
|
||||
offset = cpu_ldsw_code(env, s->pc);
|
||||
s->pc += 2;
|
||||
tcg_gen_addi_i32(tcg_ctx, tmp32, tmp32, offset);
|
||||
break;
|
||||
case 7:
|
||||
offset = cpu_ldsw_code(env, s->pc);
|
||||
offset += s->pc - 2;
|
||||
s->pc += 2;
|
||||
tcg_gen_addi_i32(tcg_ctx, tmp32, tmp32, offset);
|
||||
break;
|
||||
default:
|
||||
goto undef;
|
||||
}
|
||||
src = gen_load64(s, tmp32);
|
||||
switch ((insn >> 3) & 7) {
|
||||
case 3:
|
||||
tcg_gen_addi_i32(tcg_ctx, tmp32, tmp32, 8);
|
||||
tcg_gen_mov_i32(tcg_ctx, AREG(insn, 0), tmp32);
|
||||
break;
|
||||
case 4:
|
||||
tcg_gen_mov_i32(tcg_ctx, AREG(insn, 0), tmp32);
|
||||
break;
|
||||
}
|
||||
tcg_temp_free_i32(tcg_ctx, tmp32);
|
||||
} else {
|
||||
SRC_EA(env, tmp32, opsize, 1, NULL);
|
||||
src = tcg_temp_new_i64(tcg_ctx);
|
||||
switch (opsize) {
|
||||
case OS_LONG:
|
||||
case OS_WORD:
|
||||
case OS_BYTE:
|
||||
gen_helper_i32_to_f64(tcg_ctx, src, tcg_ctx->cpu_env, tmp32);
|
||||
break;
|
||||
case OS_SINGLE:
|
||||
gen_helper_f32_to_f64(tcg_ctx, src, tcg_ctx->cpu_env, tmp32);
|
||||
break;
|
||||
}
|
||||
cpu_src = gen_fp_result_ptr(s);
|
||||
if (gen_ea_fp(env, s, insn, opsize, cpu_src, EA_LOADS) == -1) {
|
||||
gen_addr_fault(s);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* Source register. */
|
||||
src = FREG(ext, 10);
|
||||
opsize = OS_EXTENDED;
|
||||
cpu_src = gen_fp_ptr(s, REG(ext, 10));
|
||||
}
|
||||
dest = FREG(ext, 7);
|
||||
res = tcg_temp_new_i64(tcg_ctx);
|
||||
if (opmode != 0x3a)
|
||||
tcg_gen_mov_f64(tcg_ctx, res, dest);
|
||||
|
||||
round = 1;
|
||||
set_dest = 1;
|
||||
cpu_dest = gen_fp_ptr(s, REG(ext, 7));
|
||||
switch (opmode) {
|
||||
case 0: case 0x40: case 0x44: /* fmove */
|
||||
tcg_gen_mov_f64(tcg_ctx, res, src);
|
||||
gen_fp_move(s, cpu_dest, cpu_src);
|
||||
break;
|
||||
case 1: /* fint */
|
||||
gen_helper_iround_f64(tcg_ctx, res, tcg_ctx->cpu_env, src);
|
||||
gen_helper_firound(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src);
|
||||
round = 0;
|
||||
break;
|
||||
case 3: /* fintrz */
|
||||
gen_helper_itrunc_f64(tcg_ctx, res, tcg_ctx->cpu_env, src);
|
||||
gen_helper_fitrunc(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src);
|
||||
round = 0;
|
||||
break;
|
||||
case 4: case 0x41: case 0x45: /* fsqrt */
|
||||
gen_helper_sqrt_f64(tcg_ctx, res, tcg_ctx->cpu_env, src);
|
||||
gen_helper_fsqrt(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src);
|
||||
break;
|
||||
case 0x18: case 0x58: case 0x5c: /* fabs */
|
||||
gen_helper_abs_f64(tcg_ctx, res, src);
|
||||
gen_helper_fabs(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src);
|
||||
break;
|
||||
case 0x1a: case 0x5a: case 0x5e: /* fneg */
|
||||
gen_helper_chs_f64(tcg_ctx, res, src);
|
||||
gen_helper_fchs(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src);
|
||||
break;
|
||||
case 0x20: case 0x60: case 0x64: /* fdiv */
|
||||
gen_helper_div_f64(tcg_ctx, res, tcg_ctx->cpu_env, res, src);
|
||||
gen_helper_fdiv(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src, cpu_dest);
|
||||
break;
|
||||
case 0x22: case 0x62: case 0x66: /* fadd */
|
||||
gen_helper_add_f64(tcg_ctx, res, tcg_ctx->cpu_env, res, src);
|
||||
gen_helper_fadd(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src, cpu_dest);
|
||||
break;
|
||||
case 0x23: case 0x63: case 0x67: /* fmul */
|
||||
gen_helper_mul_f64(tcg_ctx, res, tcg_ctx->cpu_env, res, src);
|
||||
gen_helper_fmul(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src, cpu_dest);
|
||||
break;
|
||||
case 0x28: case 0x68: case 0x6c: /* fsub */
|
||||
gen_helper_sub_f64(tcg_ctx, res, tcg_ctx->cpu_env, res, src);
|
||||
gen_helper_fsub(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src, cpu_dest);
|
||||
break;
|
||||
case 0x38: /* fcmp */
|
||||
gen_helper_sub_cmp_f64(tcg_ctx, res, tcg_ctx->cpu_env, res, src);
|
||||
set_dest = 0;
|
||||
round = 0;
|
||||
tcg_temp_free_ptr(tcg_ctx, cpu_dest);
|
||||
cpu_dest = gen_fp_result_ptr(s);
|
||||
gen_helper_fsub_cmp(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, cpu_src, cpu_dest);
|
||||
break;
|
||||
case 0x3a: /* ftst */
|
||||
tcg_gen_mov_f64(tcg_ctx, res, src);
|
||||
set_dest = 0;
|
||||
tcg_temp_free_ptr(tcg_ctx, cpu_dest);
|
||||
cpu_dest = gen_fp_result_ptr(s);
|
||||
gen_fp_move(s, cpu_dest, cpu_src);
|
||||
round = 0;
|
||||
break;
|
||||
default:
|
||||
goto undef;
|
||||
}
|
||||
if (ext & (1 << 14)) {
|
||||
tcg_temp_free_i64(tcg_ctx, src);
|
||||
}
|
||||
if (round) {
|
||||
if (opmode & 0x40) {
|
||||
if ((opmode & 0x4) != 0)
|
||||
|
@ -4522,16 +4708,18 @@ DISAS_INSN(fpu)
|
|||
}
|
||||
}
|
||||
if (round) {
|
||||
TCGv tmp = tcg_temp_new_i32(tcg_ctx);
|
||||
gen_helper_f64_to_f32(tcg_ctx, tmp, tcg_ctx->cpu_env, res);
|
||||
gen_helper_f32_to_f64(tcg_ctx, res, tcg_ctx->cpu_env, tmp);
|
||||
tcg_temp_free_i32(tcg_ctx, tmp);
|
||||
TCGv tmp = tcg_temp_new(tcg_ctx);
|
||||
gen_helper_redf32(tcg_ctx, tmp, tcg_ctx->cpu_env, cpu_dest);
|
||||
gen_helper_extf32(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, tmp);
|
||||
tcg_temp_free(tcg_ctx, tmp);
|
||||
} else {
|
||||
TCGv_i64 t64 = tcg_temp_new_i64(tcg_ctx);
|
||||
gen_helper_redf64(tcg_ctx, t64, tcg_ctx->cpu_env, cpu_dest);
|
||||
gen_helper_extf64(tcg_ctx, tcg_ctx->cpu_env, cpu_dest, t64);
|
||||
tcg_temp_free_i64(tcg_ctx, t64);
|
||||
}
|
||||
tcg_gen_mov_f64(tcg_ctx, tcg_ctx->QREG_FP_RESULT, res);
|
||||
if (set_dest) {
|
||||
tcg_gen_mov_f64(tcg_ctx, dest, res);
|
||||
}
|
||||
tcg_temp_free_i64(tcg_ctx, res);
|
||||
tcg_temp_free_ptr(tcg_ctx, cpu_src);
|
||||
tcg_temp_free_ptr(tcg_ctx, cpu_dest);
|
||||
return;
|
||||
undef:
|
||||
/* FIXME: Is this right for offset addressing modes? */
|
||||
|
@ -4546,6 +4734,7 @@ DISAS_INSN(fbcc)
|
|||
uint32_t addr;
|
||||
TCGv flag;
|
||||
TCGLabel *l1;
|
||||
TCGv_ptr fp_result;
|
||||
|
||||
addr = s->pc;
|
||||
offset = cpu_ldsw_code(env, s->pc);
|
||||
|
@ -4557,7 +4746,9 @@ DISAS_INSN(fbcc)
|
|||
l1 = gen_new_label(tcg_ctx);
|
||||
/* TODO: Raise BSUN exception. */
|
||||
flag = tcg_temp_new(tcg_ctx);
|
||||
gen_helper_compare_f64(tcg_ctx, flag, tcg_ctx->cpu_env, tcg_ctx->QREG_FP_RESULT);
|
||||
fp_result = gen_fp_result_ptr(s);
|
||||
gen_helper_fcompare(tcg_ctx, flag, tcg_ctx->cpu_env, fp_result);
|
||||
tcg_temp_free_ptr(tcg_ctx, fp_result);
|
||||
/* Jump to l1 if condition is true. */
|
||||
switch (insn & 0xf) {
|
||||
case 0: /* f */
|
||||
|
@ -5204,11 +5395,15 @@ void register_m68k_insns (CPUM68KState *env)
|
|||
INSN(bfop_reg, eec0, fff8, BITFIELD); /* bfset */
|
||||
INSN(bfop_mem, e8c0, ffc0, BITFIELD); /* bftst */
|
||||
INSN(bfop_reg, e8c0, fff8, BITFIELD); /* bftst */
|
||||
INSN(undef_fpu, f000, f000, CF_ISA_A);
|
||||
BASE(undef_fpu, f000, f000);
|
||||
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(fsave, f300, ffc0, CF_FPU);
|
||||
INSN(fpu, f200, ffc0, FPU);
|
||||
INSN(fbcc, f280, ff80, FPU);
|
||||
INSN(frestore, f340, ffc0, FPU);
|
||||
INSN(fsave, f300, ffc0, FPU);
|
||||
INSN(intouch, f340, ffc0, CF_ISA_A);
|
||||
INSN(cpushl, f428, ff38, CF_ISA_A);
|
||||
INSN(wddata, fb00, ff00, CF_ISA_A);
|
||||
|
|
|
@ -911,12 +911,10 @@ struct TCGContext {
|
|||
|
||||
/* qemu/target-m68k/translate.c */
|
||||
TCGv_i32 cpu_halted;
|
||||
char cpu_reg_names[3*8*3 + 5*4];
|
||||
char cpu_reg_names[2 * 8 * 3 + 5 * 4];
|
||||
TCGv cpu_dregs[8];
|
||||
TCGv cpu_aregs[8];
|
||||
TCGv_i64 cpu_fregs[8];
|
||||
TCGv_i64 cpu_macc[4];
|
||||
TCGv_i64 QREG_FP_RESULT;
|
||||
TCGv QREG_PC;
|
||||
TCGv QREG_SR;
|
||||
TCGv QREG_CC_OP;
|
||||
|
|
Loading…
Reference in a new issue