Files
86Box/src/cpu/x87_ops_sf_compare.h
2025-03-06 00:12:45 +01:00

546 lines
26 KiB
C

#define cmp_FPU(name, optype, a_size, load_var, rw, use_var, is_nan, cycle_postfix) \
static int sf_FCOM##name##_a##a_size(uint32_t fetchdat) \
{ \
floatx80 a; \
int rc; \
struct softfloat_status_t status; \
optype temp; \
FP_ENTER(); \
FPU_check_pending_exceptions(); \
fetch_ea_##a_size(fetchdat); \
SEG_CHECK_READ(cpu_state.ea_seg); \
load_var = rw; \
if (cpu_state.abrt) \
return 1; \
clear_C1(); \
if (IS_TAG_EMPTY(0)) { \
FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0); \
setcc(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3); \
goto next_ins; \
} \
status = i387cw_to_softfloat_status_word(i387_get_control_word()); \
a = FPU_read_regi(0); \
if (is_nan) { \
rc = softfloat_relation_unordered; \
softfloat_raiseFlags(&status, softfloat_flag_invalid); \
} else { \
rc = extF80_compare_normal(a, use_var, &status); \
} \
setcc(FPU_status_word_flags_fpu_compare(rc)); \
FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0); \
\
next_ins: \
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom##cycle_postfix) : ((x87_timings.fcom##cycle_postfix) * cpu_multi)); \
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom##cycle_postfix) : ((x87_concurrency.fcom##cycle_postfix) * cpu_multi)); \
return 0; \
} \
static int sf_FCOMP##name##_a##a_size(uint32_t fetchdat) \
{ \
floatx80 a; \
int rc; \
struct softfloat_status_t status; \
optype temp; \
FP_ENTER(); \
FPU_check_pending_exceptions(); \
fetch_ea_##a_size(fetchdat); \
SEG_CHECK_READ(cpu_state.ea_seg); \
load_var = rw; \
if (cpu_state.abrt) \
return 1; \
clear_C1(); \
if (IS_TAG_EMPTY(0)) { \
FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0); \
setcc(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3); \
if (is_IA_masked()) \
FPU_pop(); \
\
goto next_ins; \
} \
status = i387cw_to_softfloat_status_word(i387_get_control_word()); \
a = FPU_read_regi(0); \
if (is_nan) { \
rc = softfloat_relation_unordered; \
softfloat_raiseFlags(&status, softfloat_flag_invalid); \
} else { \
rc = extF80_compare_normal(a, use_var, &status); \
} \
setcc(FPU_status_word_flags_fpu_compare(rc)); \
if (!FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0)) \
FPU_pop(); \
\
next_ins: \
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom##cycle_postfix) : ((x87_timings.fcom##cycle_postfix) * cpu_multi)); \
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom##cycle_postfix) : ((x87_concurrency.fcom##cycle_postfix) * cpu_multi)); \
return 0; \
}
// clang-format off
cmp_FPU(s, float32, 16, temp, geteal(), f32_to_extF80(temp, &status), extF80_isNaN(a) || extF80_isUnsupported(a) || f32_isNaN(temp), _32)
#ifndef FPU_8087
cmp_FPU(s, float32, 32, temp, geteal(), f32_to_extF80(temp, &status), extF80_isNaN(a) || extF80_isUnsupported(a) || f32_isNaN(temp), _32)
#endif
cmp_FPU(d, float64, 16, temp, geteaq(), f64_to_extF80(temp, &status), extF80_isNaN(a) || extF80_isUnsupported(a) || f64_isNaN(temp), _64)
#ifndef FPU_8087
cmp_FPU(d, float64, 32, temp, geteaq(), f64_to_extF80(temp, &status), extF80_isNaN(a) || extF80_isUnsupported(a) || f64_isNaN(temp), _64)
#endif
cmp_FPU(iw, int16_t, 16, temp, (int16_t)geteaw(), i32_to_extF80((int32_t)temp), 0, _i16)
#ifndef FPU_8087
cmp_FPU(iw, int16_t, 32, temp, (int16_t)geteaw(), i32_to_extF80((int32_t)temp), 0, _i16)
#endif
cmp_FPU(il, int32_t, 16, temp, (int32_t)geteal(), i32_to_extF80(temp), 0, _i32)
#ifndef FPU_8087
cmp_FPU(il, int32_t, 32, temp, (int32_t)geteal(), i32_to_extF80(temp), 0, _i32)
#endif
// clang-format on
static int
sf_FCOM_sti(uint32_t fetchdat)
{
floatx80 a;
floatx80 b;
struct softfloat_status_t status;
int rc;
FP_ENTER();
FPU_check_pending_exceptions();
cpu_state.pc++;
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(fetchdat & 7)) {
FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0);
setcc(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
goto next_ins;
}
status = i387cw_to_softfloat_status_word(i387_get_control_word());
a = FPU_read_regi(0);
b = FPU_read_regi(fetchdat & 7);
rc = extF80_compare_normal(a, b, &status);
setcc(FPU_status_word_flags_fpu_compare(rc));
FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0);
next_ins:
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom) : (x87_timings.fcom * cpu_multi));
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom) : (x87_concurrency.fcom * cpu_multi));
return 0;
}
static int
sf_FCOMP_sti(uint32_t fetchdat)
{
floatx80 a;
floatx80 b;
struct softfloat_status_t status;
int rc;
FP_ENTER();
FPU_check_pending_exceptions();
cpu_state.pc++;
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(fetchdat & 7)) {
FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0);
setcc(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
if (is_IA_masked()) {
FPU_pop();
}
goto next_ins;
}
status = i387cw_to_softfloat_status_word(i387_get_control_word());
a = FPU_read_regi(0);
b = FPU_read_regi(fetchdat & 7);
rc = extF80_compare_normal(a, b, &status);
setcc(FPU_status_word_flags_fpu_compare(rc));
if (!FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0)) {
FPU_pop();
}
next_ins:
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom) : (x87_timings.fcom * cpu_multi));
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom) : (x87_concurrency.fcom * cpu_multi));
return 0;
}
static int
sf_FCOMPP(uint32_t fetchdat)
{
floatx80 a;
floatx80 b;
struct softfloat_status_t status;
int rc;
FP_ENTER();
FPU_check_pending_exceptions();
cpu_state.pc++;
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1)) {
FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0);
setcc(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
if (is_IA_masked()) {
FPU_pop();
FPU_pop();
}
goto next_ins;
}
status = i387cw_to_softfloat_status_word(i387_get_control_word());
a = FPU_read_regi(0);
b = FPU_read_regi(1);
rc = extF80_compare_normal(a, b, &status);
setcc(FPU_status_word_flags_fpu_compare(rc));
if (!FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0)) {
FPU_pop();
FPU_pop();
}
next_ins:
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom) : (x87_timings.fcom * cpu_multi));
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom) : (x87_concurrency.fcom * cpu_multi));
return 0;
}
#ifndef FPU_8087
static int
sf_FUCOMPP(uint32_t fetchdat)
{
floatx80 a;
floatx80 b;
struct softfloat_status_t status;
int rc;
FP_ENTER();
FPU_check_pending_exceptions();
cpu_state.pc++;
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1)) {
FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0);
setcc(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
if (is_IA_masked()) {
FPU_pop();
FPU_pop();
}
goto next_ins;
}
status = i387cw_to_softfloat_status_word(i387_get_control_word());
a = FPU_read_regi(0);
b = FPU_read_regi(1);
rc = extF80_compare_quiet(a, b, &status);
setcc(FPU_status_word_flags_fpu_compare(rc));
if (!FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0)) {
FPU_pop();
FPU_pop();
}
next_ins:
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fucom) : (x87_timings.fucom * cpu_multi));
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fucom) : (x87_concurrency.fucom * cpu_multi));
return 0;
}
#ifndef OPS_286_386
static int
sf_FCOMI_st0_stj(uint32_t fetchdat)
{
floatx80 a;
floatx80 b;
struct softfloat_status_t status;
int rc;
FP_ENTER();
FPU_check_pending_exceptions();
cpu_state.pc++;
flags_rebuild();
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(fetchdat & 7)) {
FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0);
cpu_state.flags |= (Z_FLAG | P_FLAG | C_FLAG);
goto next_ins;
}
status = i387cw_to_softfloat_status_word(i387_get_control_word());
a = FPU_read_regi(0);
b = FPU_read_regi(fetchdat & 7);
rc = extF80_compare_normal(a, b, &status);
FPU_write_eflags_fpu_compare(rc);
FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0);
next_ins:
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom) : (x87_timings.fcom * cpu_multi));
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom) : (x87_concurrency.fcom * cpu_multi));
return 0;
}
static int
sf_FCOMIP_st0_stj(uint32_t fetchdat)
{
floatx80 a;
floatx80 b;
struct softfloat_status_t status;
int rc;
FP_ENTER();
FPU_check_pending_exceptions();
cpu_state.pc++;
flags_rebuild();
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(fetchdat & 7)) {
FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0);
cpu_state.flags |= (Z_FLAG | P_FLAG | C_FLAG);
if (is_IA_masked()) {
FPU_pop();
}
goto next_ins;
}
status = i387cw_to_softfloat_status_word(i387_get_control_word());
a = FPU_read_regi(0);
b = FPU_read_regi(fetchdat & 7);
rc = extF80_compare_normal(a, b, &status);
FPU_write_eflags_fpu_compare(rc);
if (!FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0)) {
FPU_pop();
}
next_ins:
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fcom) : (x87_timings.fcom * cpu_multi));
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fcom) : (x87_concurrency.fcom * cpu_multi));
return 0;
}
#endif
static int
sf_FUCOM_sti(uint32_t fetchdat)
{
floatx80 a;
floatx80 b;
struct softfloat_status_t status;
int rc;
FP_ENTER();
FPU_check_pending_exceptions();
cpu_state.pc++;
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(fetchdat & 7)) {
FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0);
setcc(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
goto next_ins;
}
status = i387cw_to_softfloat_status_word(i387_get_control_word());
a = FPU_read_regi(0);
b = FPU_read_regi(fetchdat & 7);
rc = extF80_compare_quiet(a, b, &status);
setcc(FPU_status_word_flags_fpu_compare(rc));
FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0);
next_ins:
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fucom) : (x87_timings.fucom * cpu_multi));
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fucom) : (x87_concurrency.fucom * cpu_multi));
return 0;
}
static int
sf_FUCOMP_sti(uint32_t fetchdat)
{
floatx80 a;
floatx80 b;
struct softfloat_status_t status;
int rc;
FP_ENTER();
FPU_check_pending_exceptions();
cpu_state.pc++;
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(fetchdat & 7)) {
FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0);
setcc(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
if (is_IA_masked())
FPU_pop();
goto next_ins;
}
status = i387cw_to_softfloat_status_word(i387_get_control_word());
a = FPU_read_regi(0);
b = FPU_read_regi(fetchdat & 7);
rc = extF80_compare_quiet(a, b, &status);
setcc(FPU_status_word_flags_fpu_compare(rc));
if (!FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0))
FPU_pop();
next_ins:
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fucom) : (x87_timings.fucom * cpu_multi));
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fucom) : (x87_concurrency.fucom * cpu_multi));
return 0;
}
# ifndef OPS_286_386
static int
sf_FUCOMI_st0_stj(uint32_t fetchdat)
{
floatx80 a;
floatx80 b;
struct softfloat_status_t status;
int rc;
FP_ENTER();
FPU_check_pending_exceptions();
cpu_state.pc++;
flags_rebuild();
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(fetchdat & 7)) {
FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0);
cpu_state.flags |= (Z_FLAG | P_FLAG | C_FLAG);
goto next_ins;
}
status = i387cw_to_softfloat_status_word(i387_get_control_word());
a = FPU_read_regi(0);
b = FPU_read_regi(fetchdat & 7);
rc = extF80_compare_quiet(a, b, &status);
FPU_write_eflags_fpu_compare(rc);
FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0);
next_ins:
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fucom) : (x87_timings.fucom * cpu_multi));
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fucom) : (x87_concurrency.fucom * cpu_multi));
return 0;
}
static int
sf_FUCOMIP_st0_stj(uint32_t fetchdat)
{
floatx80 a;
floatx80 b;
struct softfloat_status_t status;
int rc;
FP_ENTER();
FPU_check_pending_exceptions();
cpu_state.pc++;
flags_rebuild();
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(fetchdat & 7)) {
FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0);
cpu_state.flags |= (Z_FLAG | P_FLAG | C_FLAG);
if (is_IA_masked())
FPU_pop();
goto next_ins;
}
status = i387cw_to_softfloat_status_word(i387_get_control_word());
a = FPU_read_regi(0);
b = FPU_read_regi(fetchdat & 7);
rc = extF80_compare_quiet(a, b, &status);
FPU_write_eflags_fpu_compare(rc);
if (!FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0))
FPU_pop();
next_ins:
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fucom) : (x87_timings.fucom * cpu_multi));
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fucom) : (x87_concurrency.fucom * cpu_multi));
return 0;
}
#endif
#endif
static int
sf_FTST(uint32_t fetchdat)
{
const floatx80 Const_Z = packFloatx80(0, 0x0000, 0);
struct softfloat_status_t status;
int rc;
FP_ENTER();
FPU_check_pending_exceptions();
cpu_state.pc++;
clear_C1();
if (IS_TAG_EMPTY(0)) {
FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0);
setcc(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
} else {
status = i387cw_to_softfloat_status_word(i387_get_control_word());
rc = extF80_compare_normal(FPU_read_regi(0), Const_Z, &status);
setcc(FPU_status_word_flags_fpu_compare(rc));
FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0);
}
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.ftst) : (x87_timings.ftst * cpu_multi));
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.ftst) : (x87_concurrency.ftst * cpu_multi));
return 0;
}
#ifndef FPU_8087
static int
sf_FTSTP(uint32_t fetchdat)
{
const floatx80 Const_Z = packFloatx80(0, 0x0000, 0);
struct softfloat_status_t status;
int rc;
FP_ENTER();
FPU_check_pending_exceptions();
cpu_state.pc++;
clear_C1();
if (IS_TAG_EMPTY(0)) {
FPU_exception(fetchdat, FPU_EX_Stack_Underflow, 0);
setcc(FPU_SW_C0 | FPU_SW_C2 | FPU_SW_C3);
} else {
status = i387cw_to_softfloat_status_word(i387_get_control_word());
rc = extF80_compare_normal(FPU_read_regi(0), Const_Z, &status);
setcc(FPU_status_word_flags_fpu_compare(rc));
FPU_exception(fetchdat, status.softfloat_exceptionFlags, 0);
FPU_pop();
}
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.ftst) : (x87_timings.ftst * cpu_multi));
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.ftst) : (x87_concurrency.ftst * cpu_multi));
return 0;
}
#endif
static int
sf_FXAM(UNUSED(uint32_t fetchdat))
{
floatx80 reg;
int sign;
softfloat_class_t aClass;
FP_ENTER();
FPU_check_pending_exceptions();
cpu_state.pc++;
reg = FPU_read_regi(0);
sign = extF80_sign(reg);
/*
* Examine the contents of the ST(0) register and sets the condition
* code flags C0, C2 and C3 in the FPU status word to indicate the
* class of value or number in the register.
*/
if (IS_TAG_EMPTY(0)) {
setcc(FPU_SW_C0 | FPU_SW_C1 | FPU_SW_C3);
} else {
aClass = extF80_class(reg);
switch (aClass) {
case softfloat_zero:
setcc(FPU_SW_C1 | FPU_SW_C3);
break;
case softfloat_SNaN:
case softfloat_QNaN:
// unsupported handled as NaNs
if (extF80_isUnsupported(reg))
setcc(FPU_SW_C1);
else
setcc(FPU_SW_C0 | FPU_SW_C1);
break;
case softfloat_negative_inf:
case softfloat_positive_inf:
setcc(FPU_SW_C0 | FPU_SW_C1 | FPU_SW_C2);
break;
case softfloat_denormal:
setcc(FPU_SW_C1 | FPU_SW_C2 | FPU_SW_C3);
break;
case softfloat_normalized:
setcc(FPU_SW_C1 | FPU_SW_C2);
break;
}
}
/*
* The C1 flag is set to the sign of the value in ST(0), regardless
* of whether the register is empty or full.
*/
if (!sign)
clear_C1();
CLOCK_CYCLES_FPU((fpu_type >= FPU_487SX) ? (x87_timings.fxam) : (x87_timings.fxam * cpu_multi));
CONCURRENCY_CYCLES((fpu_type >= FPU_487SX) ? (x87_concurrency.fxam) : (x87_concurrency.fxam * cpu_multi));
return 0;
}