in math-emu/fpu_trig.c [1486:1628]
static void fscale(FPU_REG *st0_ptr, u_char st0_tag)
{
FPU_REG *st1_ptr = &st(1);
u_char st1_tag = FPU_gettagi(1);
int old_cw = control_word;
u_char sign = getsign(st0_ptr);
clear_C1();
if (!((st0_tag ^ TAG_Valid) | (st1_tag ^ TAG_Valid))) {
long scale;
FPU_REG tmp;
/* Convert register for internal use. */
setexponent16(st0_ptr, exponent(st0_ptr));
valid_scale:
if (exponent(st1_ptr) > 30) {
/* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */
if (signpositive(st1_ptr)) {
EXCEPTION(EX_Overflow);
FPU_copy_to_reg0(&CONST_INF, TAG_Special);
} else {
EXCEPTION(EX_Underflow);
FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
}
setsign(st0_ptr, sign);
return;
}
control_word &= ~CW_RC;
control_word |= RC_CHOP;
reg_copy(st1_ptr, &tmp);
FPU_round_to_int(&tmp, st1_tag); /* This can never overflow here */
control_word = old_cw;
scale = signnegative(st1_ptr) ? -tmp.sigl : tmp.sigl;
scale += exponent16(st0_ptr);
setexponent16(st0_ptr, scale);
/* Use FPU_round() to properly detect under/overflow etc */
FPU_round(st0_ptr, 0, 0, control_word, sign);
return;
}
if (st0_tag == TAG_Special)
st0_tag = FPU_Special(st0_ptr);
if (st1_tag == TAG_Special)
st1_tag = FPU_Special(st1_ptr);
if ((st0_tag == TAG_Valid) || (st0_tag == TW_Denormal)) {
switch (st1_tag) {
case TAG_Valid:
/* st(0) must be a denormal */
if ((st0_tag == TW_Denormal)
&& (denormal_operand() < 0))
return;
FPU_to_exp16(st0_ptr, st0_ptr); /* Will not be left on stack */
goto valid_scale;
case TAG_Zero:
if (st0_tag == TW_Denormal)
denormal_operand();
return;
case TW_Denormal:
denormal_operand();
return;
case TW_Infinity:
if ((st0_tag == TW_Denormal)
&& (denormal_operand() < 0))
return;
if (signpositive(st1_ptr))
FPU_copy_to_reg0(&CONST_INF, TAG_Special);
else
FPU_copy_to_reg0(&CONST_Z, TAG_Zero);
setsign(st0_ptr, sign);
return;
case TW_NaN:
real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
return;
}
} else if (st0_tag == TAG_Zero) {
switch (st1_tag) {
case TAG_Valid:
case TAG_Zero:
return;
case TW_Denormal:
denormal_operand();
return;
case TW_Infinity:
if (signpositive(st1_ptr))
arith_invalid(0); /* Zero scaled by +Infinity */
return;
case TW_NaN:
real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
return;
}
} else if (st0_tag == TW_Infinity) {
switch (st1_tag) {
case TAG_Valid:
case TAG_Zero:
return;
case TW_Denormal:
denormal_operand();
return;
case TW_Infinity:
if (signnegative(st1_ptr))
arith_invalid(0); /* Infinity scaled by -Infinity */
return;
case TW_NaN:
real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
return;
}
} else if (st0_tag == TW_NaN) {
if (st1_tag != TAG_Empty) {
real_2op_NaN(st1_ptr, st1_tag, 0, st0_ptr);
return;
}
}
#ifdef PARANOID
if (!((st0_tag == TAG_Empty) || (st1_tag == TAG_Empty))) {
EXCEPTION(EX_INTERNAL | 0x115);
return;
}
#endif
/* At least one of st(0), st(1) must be empty */
FPU_stack_underflow();
}