-----BEGIN PGP SIGNATURE-----
iQIcBAABAgAGBQJZQkJfAAoJEPMMOL0/L748J+EQAKyUjkYxwu/bicoX8etbg2GN dZ6dWdf1r5Qn+cd+F1dL0df05mGIJcuJB3+gxRP0QeY6VcJclipXfarstIKStK0R qbGgBYLoJ9p6W6CMr1yNUW5g3P3zZs22SY/0QQYIvY+KYJqGZlgnbi73UFCvg98p jokVL+tcOHqNikvwRG4LxL478k/PC0IuYnw0bBEtno7ck4/HMlww1Dz7vffX9HBG AcPFwg4iPfUAIR3wbJXD6Yxhxbj8IRTeeMXSNjYaXec67z1970+LWZRD20laHTY1 eNib0S9gh5IaR7xLjFEJ/kacAytIbBrc3Bh4uYZLgc18eNrpRda1AGkCwrr2BDgt unKtM4/ijncbgfJ4ypb1GEzs4wNUoFe2835Vv1QKpWX4rtImvQMhAs0D2difeGja Akrdn2Co6qavqoUXXfd2PkYXdguegTHV/ZKjKOqtL6ntnKwnSPCL5lSVuk3gLT5S SmpuldNkH8r9f82YCJG1C62qBTsRlaYgJXoCvB0+nA5nJaCISCW8fG2PlEoevHs6 Q3NbK9LUfkeXKB44tTbYMhRHkQAfpW+2rBdiHqvOoJFc79C2luIha8ZQcVaq3xgE JNRdYH+YHv5utBy6VxQHrPWKUdgF6/HHXK/7XYPQUld4DHY1ujVTEfDBhGokpcDC aHB0I3TaZZmomnb0lvUR =uAMO -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/vivier/tags/m68k-for-2.10-pull-request' into staging # gpg: Signature made Thu 15 Jun 2017 09:16:31 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: define ext_opsize target-m68k: move FPU helpers to fpu_helper.c softfloat: define 680x0 specific values target/m68k: fix V flag for CC_OP_SUBx Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
5135a1056d
|
@ -111,7 +111,7 @@ float16 float16_default_nan(float_status *status)
|
|||
*----------------------------------------------------------------------------*/
|
||||
float32 float32_default_nan(float_status *status)
|
||||
{
|
||||
#if defined(TARGET_SPARC)
|
||||
#if defined(TARGET_SPARC) || defined(TARGET_M68K)
|
||||
return const_float32(0x7FFFFFFF);
|
||||
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
|
||||
defined(TARGET_XTENSA) || defined(TARGET_S390X) || defined(TARGET_TRICORE)
|
||||
|
@ -136,7 +136,7 @@ float32 float32_default_nan(float_status *status)
|
|||
*----------------------------------------------------------------------------*/
|
||||
float64 float64_default_nan(float_status *status)
|
||||
{
|
||||
#if defined(TARGET_SPARC)
|
||||
#if defined(TARGET_SPARC) || defined(TARGET_M68K)
|
||||
return const_float64(LIT64(0x7FFFFFFFFFFFFFFF));
|
||||
#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
|
||||
defined(TARGET_S390X)
|
||||
|
@ -162,7 +162,10 @@ float64 float64_default_nan(float_status *status)
|
|||
floatx80 floatx80_default_nan(float_status *status)
|
||||
{
|
||||
floatx80 r;
|
||||
|
||||
#if defined(TARGET_M68K)
|
||||
r.low = LIT64(0xFFFFFFFFFFFFFFFF);
|
||||
r.high = 0x7FFF;
|
||||
#else
|
||||
if (status->snan_bit_is_one) {
|
||||
r.low = LIT64(0xBFFFFFFFFFFFFFFF);
|
||||
r.high = 0x7FFF;
|
||||
|
@ -170,6 +173,7 @@ floatx80 floatx80_default_nan(float_status *status)
|
|||
r.low = LIT64(0xC000000000000000);
|
||||
r.high = 0xFFFF;
|
||||
}
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -502,6 +506,30 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
#elif defined(TARGET_M68K)
|
||||
static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
|
||||
flag aIsLargerSignificand)
|
||||
{
|
||||
/* M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL
|
||||
* 3.4 FLOATING-POINT INSTRUCTION DETAILS
|
||||
* If either operand, but not both operands, of an operation is a
|
||||
* nonsignaling NaN, then that NaN is returned as the result. If both
|
||||
* operands are nonsignaling NaNs, then the destination operand
|
||||
* nonsignaling NaN is returned as the result.
|
||||
* If either operand to an operation is a signaling NaN (SNaN), then the
|
||||
* SNaN bit is set in the FPSR EXC byte. If the SNaN exception enable bit
|
||||
* is set in the FPCR ENABLE byte, then the exception is taken and the
|
||||
* destination is not modified. If the SNaN exception enable bit is not
|
||||
* set, setting the SNaN bit in the operand to a one converts the SNaN to
|
||||
* a nonsignaling NaN. The operation then continues as described in the
|
||||
* preceding paragraph for nonsignaling NaNs.
|
||||
*/
|
||||
if (aIsQNaN || aIsSNaN) { /* a is the destination operand */
|
||||
return 0; /* return the destination operand */
|
||||
} else {
|
||||
return 1; /* return b */
|
||||
}
|
||||
}
|
||||
#else
|
||||
static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
|
||||
flag aIsLargerSignificand)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
obj-y += m68k-semi.o
|
||||
obj-y += translate.o op_helper.o helper.o cpu.o
|
||||
obj-y += translate.o op_helper.o helper.o cpu.o fpu_helper.o
|
||||
obj-y += gdbstub.o
|
||||
|
|
112
target/m68k/fpu_helper.c
Normal file
112
target/m68k/fpu_helper.c
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* m68k FPU helpers
|
||||
*
|
||||
* Copyright (c) 2006-2007 CodeSourcery
|
||||
* Written by Paul Brook
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/helper-proto.h"
|
||||
|
||||
uint32_t HELPER(f64_to_i32)(CPUM68KState *env, float64 val)
|
||||
{
|
||||
return float64_to_int32(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float32 HELPER(f64_to_f32)(CPUM68KState *env, float64 val)
|
||||
{
|
||||
return float64_to_float32(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(i32_to_f64)(CPUM68KState *env, uint32_t val)
|
||||
{
|
||||
return int32_to_float64(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(f32_to_f64)(CPUM68KState *env, float32 val)
|
||||
{
|
||||
return float32_to_float64(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(iround_f64)(CPUM68KState *env, float64 val)
|
||||
{
|
||||
return float64_round_to_int(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(itrunc_f64)(CPUM68KState *env, float64 val)
|
||||
{
|
||||
return float64_trunc_to_int(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(sqrt_f64)(CPUM68KState *env, float64 val)
|
||||
{
|
||||
return float64_sqrt(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(abs_f64)(float64 val)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t HELPER(compare_f64)(CPUM68KState *env, float64 val)
|
||||
{
|
||||
return float64_compare_quiet(val, float64_zero, &env->fp_status);
|
||||
}
|
|
@ -284,94 +284,6 @@ void HELPER(set_sr)(CPUM68KState *env, uint32_t val)
|
|||
m68k_switch_sp(env);
|
||||
}
|
||||
|
||||
/* FPU helpers. */
|
||||
uint32_t HELPER(f64_to_i32)(CPUM68KState *env, float64 val)
|
||||
{
|
||||
return float64_to_int32(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float32 HELPER(f64_to_f32)(CPUM68KState *env, float64 val)
|
||||
{
|
||||
return float64_to_float32(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(i32_to_f64)(CPUM68KState *env, uint32_t val)
|
||||
{
|
||||
return int32_to_float64(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(f32_to_f64)(CPUM68KState *env, float32 val)
|
||||
{
|
||||
return float32_to_float64(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(iround_f64)(CPUM68KState *env, float64 val)
|
||||
{
|
||||
return float64_round_to_int(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(itrunc_f64)(CPUM68KState *env, float64 val)
|
||||
{
|
||||
return float64_trunc_to_int(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(sqrt_f64)(CPUM68KState *env, float64 val)
|
||||
{
|
||||
return float64_sqrt(val, &env->fp_status);
|
||||
}
|
||||
|
||||
float64 HELPER(abs_f64)(float64 val)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t HELPER(compare_f64)(CPUM68KState *env, float64 val)
|
||||
{
|
||||
return float64_compare_quiet(val, float64_zero, &env->fp_status);
|
||||
}
|
||||
|
||||
/* MAC unit. */
|
||||
/* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
|
||||
|
|
|
@ -565,7 +565,7 @@ static void gen_flush_flags(DisasContext *s)
|
|||
t1 = tcg_temp_new();
|
||||
tcg_gen_add_i32(t0, QREG_CC_N, QREG_CC_V);
|
||||
gen_ext(t0, t0, s->cc_op - CC_OP_SUBB, 1);
|
||||
tcg_gen_xor_i32(t1, QREG_CC_N, QREG_CC_V);
|
||||
tcg_gen_xor_i32(t1, QREG_CC_N, t0);
|
||||
tcg_gen_xor_i32(QREG_CC_V, QREG_CC_V, t0);
|
||||
tcg_temp_free(t0);
|
||||
tcg_gen_and_i32(QREG_CC_V, QREG_CC_V, t1);
|
||||
|
@ -669,6 +669,21 @@ static inline int insn_opsize(int insn)
|
|||
}
|
||||
}
|
||||
|
||||
static inline int ext_opsize(int ext, int pos)
|
||||
{
|
||||
switch ((ext >> pos) & 7) {
|
||||
case 0: return OS_LONG;
|
||||
case 1: return OS_SINGLE;
|
||||
case 2: return OS_EXTENDED;
|
||||
case 3: return OS_PACKED;
|
||||
case 4: return OS_WORD;
|
||||
case 5: return OS_DOUBLE;
|
||||
case 6: return OS_BYTE;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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, TCGv reg, TCGv val)
|
||||
|
@ -4111,20 +4126,19 @@ DISAS_INSN(fpu)
|
|||
tmp32 = tcg_temp_new_i32();
|
||||
/* fmove */
|
||||
/* ??? TODO: Proper behavior on overflow. */
|
||||
switch ((ext >> 10) & 7) {
|
||||
case 0:
|
||||
opsize = OS_LONG;
|
||||
|
||||
opsize = ext_opsize(ext, 10);
|
||||
switch (opsize) {
|
||||
case OS_LONG:
|
||||
gen_helper_f64_to_i32(tmp32, cpu_env, src);
|
||||
break;
|
||||
case 1:
|
||||
opsize = OS_SINGLE;
|
||||
case OS_SINGLE:
|
||||
gen_helper_f64_to_f32(tmp32, cpu_env, src);
|
||||
break;
|
||||
case 4:
|
||||
opsize = OS_WORD;
|
||||
case OS_WORD:
|
||||
gen_helper_f64_to_i32(tmp32, cpu_env, src);
|
||||
break;
|
||||
case 5: /* OS_DOUBLE */
|
||||
case OS_DOUBLE:
|
||||
tcg_gen_mov_i32(tmp32, AREG(insn, 0));
|
||||
switch ((insn >> 3) & 7) {
|
||||
case 2:
|
||||
|
@ -4153,8 +4167,7 @@ DISAS_INSN(fpu)
|
|||
}
|
||||
tcg_temp_free_i32(tmp32);
|
||||
return;
|
||||
case 6:
|
||||
opsize = OS_BYTE;
|
||||
case OS_BYTE:
|
||||
gen_helper_f64_to_i32(tmp32, cpu_env, src);
|
||||
break;
|
||||
default:
|
||||
|
@ -4227,15 +4240,7 @@ DISAS_INSN(fpu)
|
|||
}
|
||||
if (ext & (1 << 14)) {
|
||||
/* Source effective address. */
|
||||
switch ((ext >> 10) & 7) {
|
||||
case 0: opsize = OS_LONG; break;
|
||||
case 1: opsize = OS_SINGLE; break;
|
||||
case 4: opsize = OS_WORD; break;
|
||||
case 5: opsize = OS_DOUBLE; break;
|
||||
case 6: opsize = OS_BYTE; break;
|
||||
default:
|
||||
goto undef;
|
||||
}
|
||||
opsize = ext_opsize(ext, 10);
|
||||
if (opsize == OS_DOUBLE) {
|
||||
tmp32 = tcg_temp_new_i32();
|
||||
tcg_gen_mov_i32(tmp32, AREG(insn, 0));
|
||||
|
|
Loading…
Reference in a new issue