-----BEGIN PGP SIGNATURE-----

iQIcBAABAgAGBQJZSt5oAAoJEPMMOL0/L748i8wP/i1y+NjCfU83ezsB/t80Qqkj
 YqvK5jU1n5xaiDFQwef9DQV4Mt+O6hYfzRO5fisIWqgowZqPuxf4pbzBQjnn+hWm
 mykBY5jLOlpUO/Swk7VYVy34Mz4zErzwTy4yUraRkMQmE7zV9rgYA+W8wfuHBZMj
 V/RBbypCfCqnsov6BTqN3rGUH4N0vrC4VIxMeOZ9o6Fcvetm5dTpK02I3ngGZPWv
 Axialdl3bpIoTpIhhGArZpsaQ7K80m/X5pYYfMAZKolTXfRVqFgK0M6P7UN8rYGI
 k0qh1x0o9xBB+4QGt1D3kR+iJi5RudWukrni3iFWe1BMegUCTRwWkXGJEhZDgdxk
 8H8XkA3JttpYQR5zLDj0po/8s34g/Hrj3ua0T0VJ4PQV7SzGk0zxRdcaoLPimfOw
 3JcfDZRaMqBXcb26orO/M/e+gtMR75TiqpxBFE6bhEBeMuN1d5oMzJCFmn0Kq5ny
 QgVML95wD6hZxSSrS7qcpZk4EbTJJp+dCJvPChiTsW2ZwofT3mMz0DBKWbd+ok5K
 wtJ91WfW2yPCOMUQsOPKZyANipLN4x4iy8jF4IZD0lj+UsalrTBNcIfyAM3RyxRR
 VTTIj9I4DknM8HNbtKao07W32WjBnxRS5jpPjKHSSw1gOjrCAf4QSw7VQnmNHh+r
 3bTxrG2lpDxYOZWPqT7T
 =lIGp
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-2.10-pull-request' into staging

# gpg: Signature made Wed 21 Jun 2017 22:00:24 BST
# gpg:                using RSA key 0xF30C38BD3F2FBE3C
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>"
# gpg:                 aka "Laurent Vivier <laurent@vivier.eu>"
# gpg:                 aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>"
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F  5173 F30C 38BD 3F2F BE3C

* remotes/vivier/tags/m68k-for-2.10-pull-request:
  target-m68k: add FPCR and FPSR
  target-m68k: define 96bit FP registers for gdb on 680x0
  target-m68k: use floatx80 internally
  target-m68k: initialize FPU registers
  target-m68k: move fmove CR to a function

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-06-22 19:01:58 +01:00
commit 4c8c1cc544
9 changed files with 1001 additions and 402 deletions

View file

@ -49,6 +49,8 @@ static void m68k_cpu_reset(CPUState *s)
M68kCPU *cpu = M68K_CPU(s);
M68kCPUClass *mcc = M68K_CPU_GET_CLASS(cpu);
CPUM68KState *env = &cpu->env;
floatx80 nan = floatx80_default_nan(NULL);
int i;
mcc->parent_reset(s);
@ -57,7 +59,12 @@ static void m68k_cpu_reset(CPUState *s)
env->sr = 0x2700;
#endif
m68k_switch_sp(env);
/* ??? FP regs should be initialized to NaN. */
for (i = 0; i < 8; i++) {
env->fregs[i].d = nan;
}
cpu_m68k_set_fpcr(env, 0);
env->fpsr = 0;
cpu_m68k_set_ccr(env, 0);
/* TODO: We should set PC from the interrupt vector. */
env->pc = 0;

View file

@ -55,8 +55,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
@ -64,6 +71,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];
@ -82,8 +91,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;
@ -162,6 +171,7 @@ int cpu_m68k_signal_handler(int host_signum, void *pinfo,
void *puc);
uint32_t cpu_m68k_get_ccr(CPUM68KState *env);
void cpu_m68k_set_ccr(CPUM68KState *env, uint32_t);
void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val);
/* Instead of computing the condition codes after each m68k instruction,
@ -206,6 +216,43 @@ typedef enum {
#define M68K_SSP 0
#define M68K_USP 1
#define M68K_FPIAR_SHIFT 0
#define M68K_FPIAR (1 << M68K_FPIAR_SHIFT)
#define M68K_FPSR_SHIFT 1
#define M68K_FPSR (1 << M68K_FPSR_SHIFT)
#define M68K_FPCR_SHIFT 2
#define M68K_FPCR (1 << M68K_FPCR_SHIFT)
/* Floating-Point Status Register */
/* Condition Code */
#define FPSR_CC_MASK 0x0f000000
#define FPSR_CC_A 0x01000000 /* Not-A-Number */
#define FPSR_CC_I 0x02000000 /* Infinity */
#define FPSR_CC_Z 0x04000000 /* Zero */
#define FPSR_CC_N 0x08000000 /* Negative */
/* Quotient */
#define FPSR_QT_MASK 0x00ff0000
/* Floating-Point Control Register */
/* Rounding mode */
#define FPCR_RND_MASK 0x0030
#define FPCR_RND_N 0x0000
#define FPCR_RND_Z 0x0010
#define FPCR_RND_M 0x0020
#define FPCR_RND_P 0x0030
/* Rounding precision */
#define FPCR_PREC_MASK 0x00c0
#define FPCR_PREC_X 0x0000
#define FPCR_PREC_S 0x0040
#define FPCR_PREC_D 0x0080
#define FPCR_PREC_U 0x00c0
#define FPCR_EXCP_MASK 0xff00
/* CACR fields are implementation defined, but some bits are common. */
#define M68K_CACR_EUSP 0x10
@ -222,8 +269,6 @@ typedef enum {
void m68k_set_irq_level(M68kCPU *cpu, int level, uint8_t vector);
void m68k_switch_sp(CPUM68KState *env);
#define M68K_FPCR_PREC (1 << 6)
void do_m68k_semihosting(CPUM68KState *env, int nr);
/* There are 4 ColdFire core ISA revisions: A, A+, B and C.
@ -301,8 +346,7 @@ static inline void cpu_get_tb_cpu_state(CPUM68KState *env, target_ulong *pc,
{
*pc = env->pc;
*cs_base = 0;
*flags = (env->fpcr & M68K_FPCR_PREC) /* Bit 6 */
| (env->sr & SR_S) /* Bit 13 */
*flags = (env->sr & SR_S) /* Bit 13 */
| ((env->macsr >> 4) & 0xf); /* Bits 0-3 */
}

View file

@ -21,92 +21,186 @@
#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)
static void m68k_restore_precision_mode(CPUM68KState *env)
{
return float64_abs(val);
}
float64 HELPER(chs_f64)(float64 val)
{
return float64_chs(val);
}
float64 HELPER(add_f64)(CPUM68KState *env, float64 a, float64 b)
{
return float64_add(a, b, &env->fp_status);
}
float64 HELPER(sub_f64)(CPUM68KState *env, float64 a, float64 b)
{
return float64_sub(a, b, &env->fp_status);
}
float64 HELPER(mul_f64)(CPUM68KState *env, float64 a, float64 b)
{
return float64_mul(a, b, &env->fp_status);
}
float64 HELPER(div_f64)(CPUM68KState *env, float64 a, float64 b)
{
return float64_div(a, b, &env->fp_status);
}
float64 HELPER(sub_cmp_f64)(CPUM68KState *env, float64 a, float64 b)
{
/* ??? 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)) {
/* +/-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);
}
}
switch (env->fpcr & FPCR_PREC_MASK) {
case FPCR_PREC_X: /* extended */
set_floatx80_rounding_precision(80, &env->fp_status);
break;
case FPCR_PREC_S: /* single */
set_floatx80_rounding_precision(32, &env->fp_status);
break;
case FPCR_PREC_D: /* double */
set_floatx80_rounding_precision(64, &env->fp_status);
break;
case FPCR_PREC_U: /* undefined */
default:
break;
}
return res;
}
uint32_t HELPER(compare_f64)(CPUM68KState *env, float64 val)
static void cf_restore_precision_mode(CPUM68KState *env)
{
return float64_compare_quiet(val, float64_zero, &env->fp_status);
if (env->fpcr & FPCR_PREC_S) { /* single */
set_floatx80_rounding_precision(32, &env->fp_status);
} else { /* double */
set_floatx80_rounding_precision(64, &env->fp_status);
}
}
static void restore_rounding_mode(CPUM68KState *env)
{
switch (env->fpcr & FPCR_RND_MASK) {
case FPCR_RND_N: /* round to nearest */
set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
break;
case FPCR_RND_Z: /* round to zero */
set_float_rounding_mode(float_round_to_zero, &env->fp_status);
break;
case FPCR_RND_M: /* round toward minus infinity */
set_float_rounding_mode(float_round_down, &env->fp_status);
break;
case FPCR_RND_P: /* round toward positive infinity */
set_float_rounding_mode(float_round_up, &env->fp_status);
break;
}
}
void cpu_m68k_set_fpcr(CPUM68KState *env, uint32_t val)
{
env->fpcr = val & 0xffff;
if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
cf_restore_precision_mode(env);
} else {
m68k_restore_precision_mode(env);
}
restore_rounding_mode(env);
}
void HELPER(fitrunc)(CPUM68KState *env, FPReg *res, FPReg *val)
{
int rounding_mode = get_float_rounding_mode(&env->fp_status);
set_float_rounding_mode(float_round_to_zero, &env->fp_status);
res->d = floatx80_round_to_int(val->d, &env->fp_status);
set_float_rounding_mode(rounding_mode, &env->fp_status);
}
void HELPER(set_fpcr)(CPUM68KState *env, uint32_t val)
{
cpu_m68k_set_fpcr(env, val);
}
void HELPER(fsqrt)(CPUM68KState *env, FPReg *res, FPReg *val)
{
res->d = floatx80_sqrt(val->d, &env->fp_status);
}
void HELPER(fabs)(CPUM68KState *env, FPReg *res, FPReg *val)
{
res->d = floatx80_abs(val->d);
}
void HELPER(fchs)(CPUM68KState *env, FPReg *res, FPReg *val)
{
res->d = floatx80_chs(val->d);
}
void HELPER(fadd)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
{
res->d = floatx80_add(val0->d, val1->d, &env->fp_status);
}
void HELPER(fsub)(CPUM68KState *env, FPReg *res, FPReg *val0, FPReg *val1)
{
res->d = floatx80_sub(val1->d, val0->d, &env->fp_status);
}
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);
}
static int float_comp_to_cc(int float_compare)
{
switch (float_compare) {
case float_relation_equal:
return FPSR_CC_Z;
case float_relation_less:
return FPSR_CC_N;
case float_relation_unordered:
return FPSR_CC_A;
case float_relation_greater:
return 0;
default:
g_assert_not_reached();
}
}
void HELPER(fcmp)(CPUM68KState *env, FPReg *val0, FPReg *val1)
{
int float_compare;
float_compare = floatx80_compare(val1->d, val0->d, &env->fp_status);
env->fpsr = (env->fpsr & ~FPSR_CC_MASK) | float_comp_to_cc(float_compare);
}
void HELPER(ftst)(CPUM68KState *env, FPReg *val)
{
uint32_t cc = 0;
if (floatx80_is_neg(val->d)) {
cc |= FPSR_CC_N;
}
if (floatx80_is_any_nan(val->d)) {
cc |= FPSR_CC_A;
} else if (floatx80_is_infinity(val->d)) {
cc |= FPSR_CC_I;
} else if (floatx80_is_zero(val->d)) {
cc |= FPSR_CC_Z;
}
env->fpsr = (env->fpsr & ~FPSR_CC_MASK) | cc;
}

View file

@ -73,28 +73,84 @@ void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf)
g_slist_free(list);
}
static int fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
{
if (n < 8) {
stfq_p(mem_buf, env->fregs[n]);
float_status s;
stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
return 8;
}
if (n < 11) {
/* FP control registers (not implemented) */
switch (n) {
case 8: /* fpcontrol */
stl_be_p(mem_buf, env->fpcr);
return 4;
case 9: /* fpstatus */
stl_be_p(mem_buf, env->fpsr);
return 4;
case 10: /* fpiar, not implemented */
memset(mem_buf, 0, 4);
return 4;
}
return 0;
}
static int fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
{
if (n < 8) {
env->fregs[n] = ldfq_p(mem_buf);
float_status s;
env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s);
return 8;
}
if (n < 11) {
/* FP control registers (not implemented) */
switch (n) {
case 8: /* fpcontrol */
cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
return 4;
case 9: /* fpstatus */
env->fpsr = ldl_p(mem_buf);
return 4;
case 10: /* fpiar, not implemented */
return 4;
}
return 0;
}
static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
{
if (n < 8) {
stw_be_p(mem_buf, env->fregs[n].l.upper);
memset(mem_buf + 2, 0, 2);
stq_be_p(mem_buf + 4, env->fregs[n].l.lower);
return 12;
}
switch (n) {
case 8: /* fpcontrol */
stl_be_p(mem_buf, env->fpcr);
return 4;
case 9: /* fpstatus */
stl_be_p(mem_buf, env->fpsr);
return 4;
case 10: /* fpiar, not implemented */
memset(mem_buf, 0, 4);
return 4;
}
return 0;
}
static int m68k_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
{
if (n < 8) {
env->fregs[n].l.upper = lduw_be_p(mem_buf);
env->fregs[n].l.lower = ldq_be_p(mem_buf + 4);
return 12;
}
switch (n) {
case 8: /* fpcontrol */
cpu_m68k_set_fpcr(env, ldl_p(mem_buf));
return 4;
case 9: /* fpstatus */
env->fpsr = ldl_p(mem_buf);
return 4;
case 10: /* fpiar, not implemented */
return 4;
}
return 0;
@ -126,8 +182,11 @@ void m68k_cpu_init_gdb(M68kCPU *cpu)
CPUM68KState *env = &cpu->env;
if (m68k_feature(env, M68K_FEATURE_CF_FPU)) {
gdb_register_coprocessor(cs, fpu_gdb_get_reg, fpu_gdb_set_reg,
gdb_register_coprocessor(cs, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg,
11, "cf-fp.xml", 18);
} else if (m68k_feature(env, M68K_FEATURE_FPU)) {
gdb_register_coprocessor(cs, m68k_fpu_gdb_get_reg,
m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18);
}
/* TODO: Add [E]MAC registers. */
}

View file

@ -12,21 +12,29 @@ 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_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(mac_move, void, env, i32, i32)
DEF_HELPER_3(macmulf, i64, env, i32, i32)

View file

@ -1,4 +1,3 @@
DEFF64(FP_RESULT, fp_result)
DEFO32(PC, pc)
DEFO32(SR, sr)
DEFO32(CC_OP, cc_op)

File diff suppressed because it is too large Load diff