Commit 1f587329 authored by blueswir1's avatar blueswir1
Browse files

128-bit float support for user mode


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3740 c046a42c-6fe2-441c-8c8c-71466251a162
parent 5cc9878d
......@@ -135,6 +135,36 @@ typedef union {
uint64_t ll;
} CPU_DoubleU;
#ifdef TARGET_SPARC
typedef union {
float128 q;
#if defined(WORDS_BIGENDIAN) \
|| (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT))
struct {
uint32_t upmost;
uint32_t upper;
uint32_t lower;
uint32_t lowest;
} l;
struct {
uint64_t upper;
uint64_t lower;
} ll;
#else
struct {
uint32_t lowest;
uint32_t lower;
uint32_t upper;
uint32_t upmost;
} l;
struct {
uint64_t lower;
uint64_t upper;
} ll;
#endif
} CPU_QuadU;
#endif
/* CPU memory access without any memory or io remapping */
/*
......
......@@ -5421,6 +5421,50 @@ int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \
COMPARE(32, 0xff)
COMPARE(64, 0x7ff)
INLINE int float128_compare_internal( float128 a, float128 b,
int is_quiet STATUS_PARAM )
{
flag aSign, bSign;
if (( ( extractFloat128Exp( a ) == 0x7fff ) &&
( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) ||
( ( extractFloat128Exp( b ) == 0x7fff ) &&
( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )) {
if (!is_quiet ||
float128_is_signaling_nan( a ) ||
float128_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid STATUS_VAR);
}
return float_relation_unordered;
}
aSign = extractFloat128Sign( a );
bSign = extractFloat128Sign( b );
if ( aSign != bSign ) {
if ( ( ( ( a.high | b.high )<<1 ) | a.low | b.low ) == 0 ) {
/* zero case */
return float_relation_equal;
} else {
return 1 - (2 * aSign);
}
} else {
if (a.low == b.low && a.high == b.high) {
return float_relation_equal;
} else {
return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) ));
}
}
}
int float128_compare( float128 a, float128 b STATUS_PARAM )
{
return float128_compare_internal(a, b, 0 STATUS_VAR);
}
int float128_compare_quiet( float128 a, float128 b STATUS_PARAM )
{
return float128_compare_internal(a, b, 1 STATUS_VAR);
}
/* Multiply A by 2 raised to the power N. */
float32 float32_scalbn( float32 a, int n STATUS_PARAM )
{
......
......@@ -415,6 +415,8 @@ int float128_lt( float128, float128 STATUS_PARAM );
int float128_eq_signaling( float128, float128 STATUS_PARAM );
int float128_le_quiet( float128, float128 STATUS_PARAM );
int float128_lt_quiet( float128, float128 STATUS_PARAM );
int float128_compare( float128, float128 STATUS_PARAM );
int float128_compare_quiet( float128, float128 STATUS_PARAM );
int float128_is_nan( float128 );
int float128_is_signaling_nan( float128 );
float128 float128_scalbn( float128, int STATUS_PARAM );
......
......@@ -212,8 +212,7 @@ Current QEMU limitations:
@item IPC syscalls are missing.
@item 128-bit floating point operations are not supported, though none of the
real CPUs implement them either. Floating point exception support is untested.
@item Floating point exception support is buggy.
@item Atomic instructions are not correctly implemented.
......
......@@ -222,6 +222,9 @@ typedef struct CPUSPARCState {
/* temporary float registers */
float32 ft0, ft1;
float64 dt0, dt1;
#if defined(CONFIG_USER_ONLY)
float128 qt0, qt1;
#endif
float_status fp_status;
#if defined(TARGET_SPARC64)
#define MAXTL 4
......
......@@ -41,6 +41,10 @@ register uint32_t T2 asm(AREG3);
#define FT1 (env->ft1)
#define DT0 (env->dt0)
#define DT1 (env->dt1)
#if defined(CONFIG_USER_ONLY)
#define QT0 (env->qt0)
#define QT1 (env->qt1)
#endif
#include "cpu.h"
#include "exec-all.h"
......@@ -65,6 +69,13 @@ void do_fcmps(void);
void do_fcmpd(void);
void do_fcmpes(void);
void do_fcmped(void);
#if defined(CONFIG_USER_ONLY)
void do_fitoq(void);
void do_fabsq(void);
void do_fsqrtq(void);
void do_fcmpq(void);
void do_fcmpeq(void);
#endif
#ifdef TARGET_SPARC64
void do_fabsd(void);
void do_fcmps_fcc1(void);
......@@ -79,6 +90,14 @@ void do_fcmpes_fcc2(void);
void do_fcmped_fcc2(void);
void do_fcmpes_fcc3(void);
void do_fcmped_fcc3(void);
#if defined(CONFIG_USER_ONLY)
void do_fcmpq_fcc1(void);
void do_fcmpq_fcc2(void);
void do_fcmpq_fcc3(void);
void do_fcmpeq_fcc1(void);
void do_fcmpeq_fcc2(void);
void do_fcmpeq_fcc3(void);
#endif
void do_popc();
void do_wrpstate();
void do_done();
......
......@@ -77,5 +77,52 @@ void OPPROTO glue(op_store_DT1_fpr_fpr, REGNAME)(void)
*p = u.l.upper;
}
#if defined(CONFIG_USER_ONLY)
/* quad floating point registers moves */
void OPPROTO glue(op_load_fpr_QT0_fpr, REGNAME)(void)
{
CPU_QuadU u;
uint32_t *p = (uint32_t *)&REG;
u.l.lowest = *(p + 3);
u.l.lower = *(p + 2);
u.l.upper = *(p + 1);
u.l.upmost = *p;
QT0 = u.q;
}
void OPPROTO glue(op_store_QT0_fpr_fpr, REGNAME)(void)
{
CPU_QuadU u;
uint32_t *p = (uint32_t *)&REG;
u.q = QT0;
*(p + 3) = u.l.lowest;
*(p + 2) = u.l.lower;
*(p + 1) = u.l.upper;
*p = u.l.upmost;
}
void OPPROTO glue(op_load_fpr_QT1_fpr, REGNAME)(void)
{
CPU_QuadU u;
uint32_t *p = (uint32_t *)&REG;
u.l.lowest = *(p + 3);
u.l.lower = *(p + 2);
u.l.upper = *(p + 1);
u.l.upmost = *p;
QT1 = u.q;
}
void OPPROTO glue(op_store_QT1_fpr_fpr, REGNAME)(void)
{
CPU_QuadU u;
uint32_t *p = (uint32_t *)&REG;
u.q = QT1;
*(p + 3) = u.l.lowest;
*(p + 2) = u.l.lower;
*(p + 1) = u.l.upper;
*p = u.l.upmost;
}
#endif
#undef REG
#undef REGNAME
......@@ -1581,6 +1581,7 @@ void OPPROTO op_clear_ieee_excp_and_FTT(void)
#define F_OP(name, p) void OPPROTO op_f##name##p(void)
#if defined(CONFIG_USER_ONLY)
#define F_BINOP(name) \
F_OP(name, s) \
{ \
......@@ -1593,7 +1594,28 @@ void OPPROTO op_clear_ieee_excp_and_FTT(void)
set_float_exception_flags(0, &env->fp_status); \
DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \
check_ieee_exceptions(); \
} \
F_OP(name, q) \
{ \
set_float_exception_flags(0, &env->fp_status); \
QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \
check_ieee_exceptions(); \
}
#else
#define F_BINOP(name) \
F_OP(name, s) \
{ \
set_float_exception_flags(0, &env->fp_status); \
FT0 = float32_ ## name (FT0, FT1, &env->fp_status); \
check_ieee_exceptions(); \
} \
F_OP(name, d) \
{ \
set_float_exception_flags(0, &env->fp_status); \
DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \
check_ieee_exceptions(); \
}
#endif
F_BINOP(add);
F_BINOP(sub);
......@@ -1610,6 +1632,18 @@ void OPPROTO op_fsmuld(void)
check_ieee_exceptions();
}
#if defined(CONFIG_USER_ONLY)
void OPPROTO op_fdmulq(void)
{
set_float_exception_flags(0, &env->fp_status);
QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status),
float64_to_float128(DT1, &env->fp_status),
&env->fp_status);
check_ieee_exceptions();
}
#endif
#if defined(CONFIG_USER_ONLY)
#define F_HELPER(name) \
F_OP(name, s) \
{ \
......@@ -1618,7 +1652,22 @@ void OPPROTO op_fsmuld(void)
F_OP(name, d) \
{ \
do_f##name##d(); \
} \
F_OP(name, q) \
{ \
do_f##name##q(); \
}
#else
#define F_HELPER(name) \
F_OP(name, s) \
{ \
do_f##name##s(); \
} \
F_OP(name, d) \
{ \
do_f##name##d(); \
}
#endif
F_HELPER(sqrt);
......@@ -1646,6 +1695,18 @@ F_OP(abs, d)
do_fabsd();
}
#if defined(CONFIG_USER_ONLY)
F_OP(neg, q)
{
QT0 = float128_chs(QT1);
}
F_OP(abs, q)
{
do_fabsd();
}
#endif
void OPPROTO op_fcmps_fcc1(void)
{
do_fcmps_fcc1();
......@@ -1706,6 +1767,38 @@ void OPPROTO op_fcmped_fcc3(void)
do_fcmped_fcc3();
}
#if defined(CONFIG_USER_ONLY)
void OPPROTO op_fcmpq_fcc1(void)
{
do_fcmpq_fcc1();
}
void OPPROTO op_fcmpq_fcc2(void)
{
do_fcmpq_fcc2();
}
void OPPROTO op_fcmpq_fcc3(void)
{
do_fcmpq_fcc3();
}
void OPPROTO op_fcmpeq_fcc1(void)
{
do_fcmpeq_fcc1();
}
void OPPROTO op_fcmpeq_fcc2(void)
{
do_fcmpeq_fcc2();
}
void OPPROTO op_fcmpeq_fcc3(void)
{
do_fcmpeq_fcc3();
}
#endif
#endif
/* Integer to float conversion. */
......@@ -1729,6 +1822,15 @@ F_OP(ito, d)
check_ieee_exceptions();
}
#if defined(CONFIG_USER_ONLY)
F_OP(ito, q)
{
set_float_exception_flags(0, &env->fp_status);
QT0 = int32_to_float128(*((int32_t *)&FT1), &env->fp_status);
check_ieee_exceptions();
}
#endif
#ifdef TARGET_SPARC64
F_OP(xto, s)
{
......@@ -1743,6 +1845,14 @@ F_OP(xto, d)
DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
check_ieee_exceptions();
}
#if defined(CONFIG_USER_ONLY)
F_OP(xto, q)
{
set_float_exception_flags(0, &env->fp_status);
QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status);
check_ieee_exceptions();
}
#endif
#endif
#endif
#undef F_HELPER
......@@ -1762,6 +1872,36 @@ void OPPROTO op_fstod(void)
check_ieee_exceptions();
}
#if defined(CONFIG_USER_ONLY)
void OPPROTO op_fqtos(void)
{
set_float_exception_flags(0, &env->fp_status);
FT0 = float128_to_float32(QT1, &env->fp_status);
check_ieee_exceptions();
}
void OPPROTO op_fstoq(void)
{
set_float_exception_flags(0, &env->fp_status);
QT0 = float32_to_float128(FT1, &env->fp_status);
check_ieee_exceptions();
}
void OPPROTO op_fqtod(void)
{
set_float_exception_flags(0, &env->fp_status);
DT0 = float128_to_float64(QT1, &env->fp_status);
check_ieee_exceptions();
}
void OPPROTO op_fdtoq(void)
{
set_float_exception_flags(0, &env->fp_status);
QT0 = float64_to_float128(DT1, &env->fp_status);
check_ieee_exceptions();
}
#endif
/* Float to integer conversion. */
void OPPROTO op_fstoi(void)
{
......@@ -1777,6 +1917,15 @@ void OPPROTO op_fdtoi(void)
check_ieee_exceptions();
}
#if defined(CONFIG_USER_ONLY)
void OPPROTO op_fqtoi(void)
{
set_float_exception_flags(0, &env->fp_status);
*((int32_t *)&FT0) = float128_to_int32_round_to_zero(QT1, &env->fp_status);
check_ieee_exceptions();
}
#endif
#ifdef TARGET_SPARC64
void OPPROTO op_fstox(void)
{
......@@ -1792,6 +1941,15 @@ void OPPROTO op_fdtox(void)
check_ieee_exceptions();
}
#if defined(CONFIG_USER_ONLY)
void OPPROTO op_fqtox(void)
{
set_float_exception_flags(0, &env->fp_status);
*((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status);
check_ieee_exceptions();
}
#endif
void OPPROTO op_fmovs_cc(void)
{
if (T2)
......@@ -1804,6 +1962,14 @@ void OPPROTO op_fmovd_cc(void)
DT0 = DT1;
}
#if defined(CONFIG_USER_ONLY)
void OPPROTO op_fmovq_cc(void)
{
if (T2)
QT0 = QT1;
}
#endif
void OPPROTO op_mov_cc(void)
{
if (T2)
......
......@@ -97,6 +97,13 @@ void do_fabsd(void)
{
DT0 = float64_abs(DT1);
}
#if defined(CONFIG_USER_ONLY)
void do_fabsq(void)
{
QT0 = float128_abs(QT1);
}
#endif
#endif
void do_fsqrts(void)
......@@ -113,6 +120,15 @@ void do_fsqrtd(void)
check_ieee_exceptions();
}
#if defined(CONFIG_USER_ONLY)
void do_fsqrtq(void)
{
set_float_exception_flags(0, &env->fp_status);
QT0 = float128_sqrt(QT1, &env->fp_status);
check_ieee_exceptions();
}
#endif
#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \
void glue(do_, name) (void) \
{ \
......@@ -148,6 +164,11 @@ GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1);
GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
#ifdef CONFIG_USER_ONLY
GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
#endif
#ifdef TARGET_SPARC64
GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0);
GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
......@@ -166,6 +187,14 @@ GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1);
GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
#ifdef CONFIG_USER_ONLY
GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
#endif
#endif
#ifndef TARGET_SPARC64
......@@ -1374,6 +1403,11 @@ void helper_ldf_asi(int asi, int size, int rd)
case 8:
*((int64_t *)&DT0) = T1;
break;
#if defined(CONFIG_USER_ONLY)
case 16:
// XXX
break;
#endif
}
T1 = tmp_T1;
}
......@@ -1417,6 +1451,11 @@ void helper_stf_asi(int asi, int size, int rd)
case 8:
T1 = *((int64_t *)&DT0);
break;
#if defined(CONFIG_USER_ONLY)
case 16:
// XXX
break;
#endif
}
helper_st_asi(asi, size);
T1 = tmp_T1;
......
......@@ -85,6 +85,28 @@ void OPPROTO glue(op_lddf, MEMSUFFIX) (void)
DT0 = glue(ldfq, MEMSUFFIX)(ADDR(T0));
}
#if defined(CONFIG_USER_ONLY)
void OPPROTO glue(op_ldqf, MEMSUFFIX) (void)
{
// XXX add 128 bit load
CPU_QuadU u;
u.ll.upper = glue(ldq, MEMSUFFIX)(ADDR(T0));
u.ll.lower = glue(ldq, MEMSUFFIX)(ADDR(T0 + 8));
QT0 = u.q;
}
void OPPROTO glue(op_stqf, MEMSUFFIX) (void)
{
// XXX add 128 bit store
CPU_QuadU u;
u.q = QT0;
glue(stq, MEMSUFFIX)(ADDR(T0), u.ll.upper);
glue(stq, MEMSUFFIX)(ADDR(T0 + 8), u.ll.lower);
}
#endif
#ifdef TARGET_SPARC64
void OPPROTO glue(op_lduw, MEMSUFFIX)(void)
{
......
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment