home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_300
/
359_11
/
patch5.000
/
EMU387
/
E17.CC
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-11
|
5KB
|
298 lines
#include "emu.h"
#include "rmov.h"
#include "const.h"
extern "C" void shld(void *);
extern "C" void shrd(void *);
int fprem_do(reg& quot, reg& div, int round) // remainder of st() / st(1)
{
int rv;
int old_cw = control_word;
control_word &= ~CW_RC;
control_word |= round;
int expdif = quot.exp - div.exp;
if (expdif < 64)
{
reg tmp, tmp2;
r_div(quot, div, tmp);
long q;
r_mov(tmp, &q);
r_mov(&q, tmp);
r_mul(div, tmp, tmp2);
r_sub(quot, tmp2, tmp);
r_mov(tmp, quot);
rv = q & 7;
}
else
{
reg tmp, tmp2;
setcc(SW_C2);
r_div(st, div, tmp);
int old_exp = tmp.exp;
tmp.exp &= 31;
long q;
r_mov(tmp, &q);
r_mov(&q, tmp);
tmp.exp = old_exp;
r_mul(div, tmp, tmp2);
r_sub(quot, tmp2, tmp);
r_mov(tmp, quot);
rv = -1;
}
control_word = old_cw;
return rv;;
}
void fprem()
{
if (empty(1))
return;
int q = fprem_do(st(), st(1), RC_CHOP);
if (q == -1)
setcc(SW_C2);
else
{
int c = 0;
if (q&4) c |= SW_C3;
if (q&2) c |= SW_C1;
if (q&1) c |= SW_C0;
setcc(c);
}
}
void fyl2xp1()
{
if (empty())
return;
reg frac2, sum, div, term, pow, temp;
r_mov(st(), frac2);
r_add(st(), CONST_2, div);
r_div(frac2, div, sum);
r_mul(sum, sum, frac2);
r_mul(sum, st(1), pow);
for (long i=3; i<15; i+=2)
{
r_mul(pow, frac2, temp);
r_mov(temp, pow);
r_mov(&i, div);
r_div(temp, div, term);
r_add(term, sum, temp);
r_mov(temp, sum);
}
r_div(sum, CONST_LN2, temp);
temp.exp++;
r_mov(temp, st(1));
st().tag = TW_E;
top++;
}
void fsqrt()
{
if (empty())
return;
if (st().tag == TW_Z)
return;
if (st().exp == EXP_MAX)
return;
if (st().sign == SIGN_NEG)
return exception(EX_I);
unsigned long long val = *(unsigned long long *)(&st().sigl);
unsigned long long result = 0;
unsigned long long side = 0;
unsigned long long left = 0;
int digit = 0;
int i;
if (st().exp & 1)
{
shrd(&val);
st().exp++;
}
int exp = (st().exp - EXP_BIAS - 1)/2 - 64;
while (!(((long *)&result)[1] & 0x80000000))
{
left = (left << 2) + (val >> 62);
shld(&val);
shld(&val);
if (left >= side*2 + 1)
{
left -= side*2+1;
side = (side+1)*2;
shld(&result);
result |= 1;
}
else
{
side *= 2;
shld(&result);
}
exp++;
}
st().exp = exp + EXP_BIAS;
st().sigl = result & 0xffffffff;
st().sigh = result >> 32;
st().tag = TW_V;
}
void fsincos()
{
if (empty())
return;
int q = fprem_do(st(), CONST_PI2, RC_CHOP);
if (q & 1)
{
reg tmp;
r_sub(CONST_PI2, st(), tmp);
r_mov(tmp, st());
}
reg x2, val, rv, tmp, t2;
reg valc, rvc, tmpc;
r_mov(st(), val);
r_mul(st(), val, x2);
r_mov(val, rv);
r_mov(CONST_1, valc);
r_mov(valc, rvc);
for (int i=0; i<11; i++)
{
val.sign ^= SIGN_POS ^ SIGN_NEG;
valc.sign ^= SIGN_POS ^ SIGN_NEG;
r_mul(x2, val, tmp);
r_mul(x2, valc, tmpc);
long c = ((i<<1)+2) * ((i<<1)+3);
r_mov(&c, t2);
r_div(tmp, t2, val);
c = ((i<<1)+1) * ((i<<1)+2);
r_mov(&c, t2);
r_div(tmpc, t2, valc);
r_add(val, rv, tmp);
r_mov(tmp, rv);
r_add(valc, rvc, tmpc);
r_mov(tmpc, rvc);
}
setcc(0);
if (q & 2)
rv.sign ^= SIGN_POS ^ SIGN_NEG;
r_mov(rv, st());
top--;
register int qq = q & 3;
if ((qq == 1) || (qq == 2))
rvc.sign ^= SIGN_POS ^ SIGN_NEG;
r_mov(rvc, st());
}
void frndint()
{
if (empty())
return;
long long tmp;
if (st().exp > EXP_BIAS+62)
return;
r_mov(st(), &tmp);
r_mov(&tmp, st());
}
void fscale()
{
long scale;
if (empty(1))
return;
r_mov(st(1), &scale);
st().exp += scale;
}
void fsin()
{
if (empty())
return;
int q = fprem_do(st(), CONST_PI2, RC_CHOP);
if (q & 1)
{
reg tmp;
r_sub(CONST_PI2, st(), tmp);
r_mov(tmp, st());
}
reg x2, val, rv, tmp, t2;
r_mov(st(), val);
r_mul(st(), val, x2);
r_mov(val, rv);
for (int i=0; i<11; i++)
{
long c = ((i<<1)+2) * ((i<<1)+3);
val.sign ^= SIGN_POS ^ SIGN_NEG;
r_mul(x2, val, tmp);
r_mov(&c, t2);
r_div(tmp, t2, val);
r_add(val, rv, tmp);
r_mov(tmp, rv);
}
setcc(0);
if (q & 2)
rv.sign ^= SIGN_POS ^ SIGN_NEG;
r_mov(rv, st());
}
void fcos()
{
if (empty())
return;
int q = fprem_do(st(), CONST_PI2, RC_CHOP);
if (q & 1)
{
reg tmp;
r_sub(CONST_PI2, st(), tmp);
r_mov(tmp, st());
}
reg x2, val, rv, tmp, t2;
r_mov(st(), val);
r_mul(st(), val, x2);
r_mov(CONST_1, val);
r_mov(val, rv);
for (int i=0; i<11; i++)
{
long c = ((i<<1)+1) * ((i<<1)+2);
val.sign ^= SIGN_POS ^ SIGN_NEG;
r_mul(x2, val, tmp);
r_mov(&c, t2);
r_div(tmp, t2, val);
r_add(val, rv, tmp);
r_mov(tmp, rv);
}
setcc(0);
register int qq = q & 3;
if ((qq == 1) || (qq == 2))
rv.sign ^= SIGN_POS ^ SIGN_NEG;
r_mov(rv, st());
}
FUNC emu_17_table[] = {
fprem, fyl2xp1, fsqrt, fsincos, frndint, fscale, fsin, fcos
};
void emu_17()
{
if (modrm > 0277)
{
(emu_17_table[modrm&7])();
}
else
{
// fstcw m16int
*(short *)get_modrm() = control_word;
}
}