target/m68k: add fmovem

Backports commit a1e58ddcb3eed7ec4a158512b9dae46f90492c1b from qemu
This commit is contained in:
Laurent Vivier 2018-03-03 21:03:51 -05:00 committed by Lioncash
parent 50b639098c
commit 8a7f7242cc
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
3 changed files with 189 additions and 30 deletions

View file

@ -22,6 +22,7 @@
#include "cpu.h"
#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
/* Undefined offsets may be different on various FPU.
* On 68040 they return 0.0 (floatx80_zero)
@ -400,3 +401,121 @@ void HELPER(fconst)(CPUM68KState *env, FPReg *val, uint32_t offset)
val->d = fpu_rom[offset];
}
typedef int (*float_access)(CPUM68KState *env, uint32_t addr, FPReg *fp,
uintptr_t ra);
static uint32_t fmovem_predec(CPUM68KState *env, uint32_t addr, uint32_t mask,
float_access access)
{
uintptr_t ra = GETPC();
int i, size;
for (i = 7; i >= 0; i--, mask <<= 1) {
if (mask & 0x80) {
size = access(env, addr, &env->fregs[i], ra);
if ((mask & 0xff) != 0x80) {
addr -= size;
}
}
}
return addr;
}
static uint32_t fmovem_postinc(CPUM68KState *env, uint32_t addr, uint32_t mask,
float_access access)
{
uintptr_t ra = GETPC();
int i, size;
for (i = 0; i < 8; i++, mask <<= 1) {
if (mask & 0x80) {
size = access(env, addr, &env->fregs[i], ra);
addr += size;
}
}
return addr;
}
static int cpu_ld_floatx80_ra(CPUM68KState *env, uint32_t addr, FPReg *fp,
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;
return 12;
}
static int 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);
return 12;
}
static int cpu_ld_float64_ra(CPUM68KState *env, uint32_t addr, FPReg *fp,
uintptr_t ra)
{
uint64_t val;
val = cpu_ldq_data_ra(env, addr, ra);
fp->d = float64_to_floatx80(*(float64 *)&val, &env->fp_status);
return 8;
}
static int 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);
return 8;
}
uint32_t HELPER(fmovemx_st_predec)(CPUM68KState *env, uint32_t addr,
uint32_t mask)
{
return fmovem_predec(env, addr, mask, cpu_st_floatx80_ra);
}
uint32_t HELPER(fmovemx_st_postinc)(CPUM68KState *env, uint32_t addr,
uint32_t mask)
{
return fmovem_postinc(env, addr, mask, cpu_st_floatx80_ra);
}
uint32_t HELPER(fmovemx_ld_postinc)(CPUM68KState *env, uint32_t addr,
uint32_t mask)
{
return fmovem_postinc(env, addr, mask, cpu_ld_floatx80_ra);
}
uint32_t HELPER(fmovemd_st_predec)(CPUM68KState *env, uint32_t addr,
uint32_t mask)
{
return fmovem_predec(env, addr, mask, cpu_st_float64_ra);
}
uint32_t HELPER(fmovemd_st_postinc)(CPUM68KState *env, uint32_t addr,
uint32_t mask)
{
return fmovem_postinc(env, addr, mask, cpu_st_float64_ra);
}
uint32_t HELPER(fmovemd_ld_postinc)(CPUM68KState *env, uint32_t addr,
uint32_t mask)
{
return fmovem_postinc(env, addr, mask, cpu_ld_float64_ra);
}

View file

@ -56,6 +56,12 @@ 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(fmovemx_st_predec, i32, env, i32, i32)
DEF_HELPER_3(fmovemx_st_postinc, i32, env, i32, i32)
DEF_HELPER_3(fmovemx_ld_postinc, i32, env, i32, i32)
DEF_HELPER_3(fmovemd_st_predec, i32, env, i32, i32)
DEF_HELPER_3(fmovemd_st_postinc, i32, env, i32, i32)
DEF_HELPER_3(fmovemd_ld_postinc, i32, env, i32, i32)
DEF_HELPER_3(mac_move, void, env, i32, i32)
DEF_HELPER_3(macmulf, i64, env, i32, i32)

View file

@ -4681,6 +4681,67 @@ static void gen_op_fmove_fcr(CPUM68KState *env, DisasContext *s,
tcg_temp_free_i32(tcg_ctx, addr);
}
static void gen_op_fmovem(CPUM68KState *env, DisasContext *s,
uint32_t insn, uint32_t ext)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
int opsize;
TCGv addr, tmp;
int mode = (ext >> 11) & 0x3;
int is_load = ((ext & 0x2000) == 0);
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_temp_new(tcg_ctx);
if (mode & 0x1) {
/* Dynamic register list */
tcg_gen_ext8u_i32(tcg_ctx, tmp, DREG(ext, 4));
} else {
/* Static register list */
tcg_gen_movi_i32(tcg_ctx, tmp, ext & 0xff);
}
if (!is_load && (mode & 2) == 0) {
/* predecrement addressing mode
* only available to store register to memory
*/
if (opsize == OS_EXTENDED) {
gen_helper_fmovemx_st_predec(tcg_ctx, tmp, tcg_ctx->cpu_env, addr, tmp);
} else {
gen_helper_fmovemd_st_predec(tcg_ctx, tmp, tcg_ctx->cpu_env, addr, tmp);
}
} else {
/* postincrement addressing mode */
if (opsize == OS_EXTENDED) {
if (is_load) {
gen_helper_fmovemx_ld_postinc(tcg_ctx, tmp, tcg_ctx->cpu_env, addr, tmp);
} else {
gen_helper_fmovemx_st_postinc(tcg_ctx, tmp, tcg_ctx->cpu_env, addr, tmp);
}
} else {
if (is_load) {
gen_helper_fmovemd_ld_postinc(tcg_ctx, tmp, tcg_ctx->cpu_env, addr, tmp);
} else {
gen_helper_fmovemd_st_postinc(tcg_ctx, tmp, tcg_ctx->cpu_env, addr, tmp);
}
}
}
if ((insn & 070) == 030 || (insn & 070) == 040) {
tcg_gen_mov_i32(tcg_ctx, AREG(insn, 0), tmp);
}
tcg_temp_free(tcg_ctx, tmp);
}
/* ??? FP exceptions are not implemented. Most exceptions are deferred until
immediately before the next FP instruction is executed. */
DISAS_INSN(fpu)
@ -4688,7 +4749,6 @@ DISAS_INSN(fpu)
TCGContext *tcg_ctx = s->uc->tcg_ctx;
uint16_t ext;
int opmode;
TCGv tmp32;
int opsize;
TCGv_ptr cpu_src, cpu_dest;
@ -4725,36 +4785,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_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) {
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);
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)) {