2009-05-02 23:12:18 +02:00
|
|
|
/*
|
2009-05-03 00:18:08 +02:00
|
|
|
* Copyright (C) 2002-2006 The DOSBox Team
|
2009-05-02 23:12:18 +02:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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
|
2009-05-03 00:02:15 +02:00
|
|
|
* GNU General Public License for more details.
|
2009-05-02 23:12:18 +02:00
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
2009-05-03 00:18:08 +02:00
|
|
|
/* $Id: fpu_instructions.h,v 1.28 2006/02/09 11:47:48 qbix79 Exp $ */
|
2009-05-02 23:43:00 +02:00
|
|
|
|
|
|
|
|
|
|
|
static void FPU_FINIT(void) {
|
|
|
|
FPU_SetCW(0x37F);
|
2009-05-03 00:18:08 +02:00
|
|
|
fpu.sw = 0;
|
2009-05-02 23:43:00 +02:00
|
|
|
TOP=FPU_GET_TOP();
|
2009-05-03 00:18:08 +02:00
|
|
|
fpu.tags[0] = TAG_Empty;
|
|
|
|
fpu.tags[1] = TAG_Empty;
|
|
|
|
fpu.tags[2] = TAG_Empty;
|
|
|
|
fpu.tags[3] = TAG_Empty;
|
|
|
|
fpu.tags[4] = TAG_Empty;
|
|
|
|
fpu.tags[5] = TAG_Empty;
|
|
|
|
fpu.tags[6] = TAG_Empty;
|
|
|
|
fpu.tags[7] = TAG_Empty;
|
|
|
|
fpu.tags[8] = TAG_Valid; // is only used by us
|
2009-05-02 23:43:00 +02:00
|
|
|
}
|
2009-05-03 00:18:08 +02:00
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
static void FPU_FCLEX(void){
|
2009-05-03 00:18:08 +02:00
|
|
|
fpu.sw &= 0x7f00; //should clear exceptions
|
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
|
|
|
|
static void FPU_FNOP(void){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_PUSH(double in){
|
|
|
|
TOP = (TOP - 1) &7;
|
|
|
|
//actually check if empty
|
2009-05-03 00:18:08 +02:00
|
|
|
fpu.tags[TOP] = TAG_Valid;
|
|
|
|
fpu.regs[TOP].d = in;
|
2009-05-02 23:43:00 +02:00
|
|
|
// LOG(LOG_FPU,LOG_ERROR)("Pushed at %d %g to the stack",newtop,in);
|
|
|
|
return;
|
|
|
|
}
|
2009-05-03 00:18:08 +02:00
|
|
|
|
|
|
|
static void FPU_PREP_PUSH(void){
|
|
|
|
TOP = (TOP - 1) &7;
|
|
|
|
fpu.tags[TOP] = TAG_Valid;
|
2009-05-02 23:43:00 +02:00
|
|
|
}
|
2009-05-03 00:18:08 +02:00
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
static void FPU_FPOP(void){
|
|
|
|
fpu.tags[TOP]=TAG_Empty;
|
|
|
|
//maybe set zero in it as well
|
|
|
|
TOP = ((TOP+1)&7);
|
|
|
|
// LOG(LOG_FPU,LOG_ERROR)("popped from %d %g off the stack",top,fpu.regs[top].d);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-05-03 00:18:08 +02:00
|
|
|
static double FROUND(double in){
|
|
|
|
switch(fpu.round){
|
|
|
|
case ROUND_Nearest:
|
|
|
|
if (in-floor(in)>0.5) return (floor(in)+1);
|
|
|
|
else if (in-floor(in)<0.5) return (floor(in));
|
|
|
|
else return (((static_cast<Bit64s>(floor(in)))&1)!=0)?(floor(in)+1):(floor(in));
|
|
|
|
break;
|
|
|
|
case ROUND_Down:
|
|
|
|
return (floor(in));
|
|
|
|
break;
|
|
|
|
case ROUND_Up:
|
|
|
|
return (ceil(in));
|
|
|
|
break;
|
|
|
|
case ROUND_Chop:
|
|
|
|
return in; //the cast afterwards will do it right maybe cast here
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return in;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define BIAS80 16383
|
|
|
|
#define BIAS64 1023
|
|
|
|
|
|
|
|
static Real64 FPU_FLD80(PhysPt addr) {
|
|
|
|
struct {
|
|
|
|
Bit16s begin;
|
|
|
|
FPU_Reg eind;
|
|
|
|
} test;
|
|
|
|
test.eind.l.lower = mem_readd(addr);
|
|
|
|
test.eind.l.upper = mem_readd(addr+4);
|
|
|
|
test.begin = mem_readw(addr+8);
|
|
|
|
|
|
|
|
Bit64s exp64 = (((test.begin&0x7fff) - BIAS80));
|
|
|
|
Bit64s blah = ((exp64 >0)?exp64:-exp64)&0x3ff;
|
|
|
|
Bit64s exp64final = ((exp64 >0)?blah:-blah) +BIAS64;
|
|
|
|
|
|
|
|
Bit64s mant64 = (test.eind.ll >> 11) & LONGTYPE(0xfffffffffffff);
|
|
|
|
Bit64s sign = (test.begin&0x8000)?1:0;
|
|
|
|
FPU_Reg result;
|
|
|
|
result.ll = (sign <<63)|(exp64final << 52)| mant64;
|
|
|
|
return result.d;
|
|
|
|
|
|
|
|
//mant64= test.mant80/2***64 * 2 **53
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_ST80(PhysPt addr,Bitu reg) {
|
|
|
|
struct {
|
|
|
|
Bit16s begin;
|
|
|
|
FPU_Reg eind;
|
|
|
|
} test;
|
|
|
|
Bit64s sign80 = (fpu.regs[reg].ll&LONGTYPE(0x8000000000000000))?1:0;
|
|
|
|
Bit64s exp80 = fpu.regs[reg].ll&LONGTYPE(0x7ff0000000000000);
|
|
|
|
Bit64s exp80final = (exp80>>52) - BIAS64 + BIAS80;
|
|
|
|
Bit64s mant80 = fpu.regs[reg].ll&LONGTYPE(0x000fffffffffffff);
|
|
|
|
Bit64s mant80final = (mant80 << 11);
|
|
|
|
// Elvira wants the 8 and tcalc doesn't
|
|
|
|
if(fpu.regs[reg].d != 0) mant80final |= LONGTYPE(0x8000000000000000);
|
|
|
|
test.begin= (static_cast<Bit16s>(sign80)<<15)| static_cast<Bit16s>(exp80final);
|
|
|
|
test.eind.ll = mant80final;
|
|
|
|
mem_writed(addr,test.eind.l.lower);
|
|
|
|
mem_writed(addr+4,test.eind.l.upper);
|
|
|
|
mem_writew(addr+8,test.begin);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void FPU_FLD_F32(PhysPt addr,Bitu store_to) {
|
|
|
|
union {
|
|
|
|
float f;
|
|
|
|
Bit32u l;
|
|
|
|
} blah;
|
|
|
|
blah.l = mem_readd(addr);
|
|
|
|
fpu.regs[store_to].d = static_cast<Real64>(blah.f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FLD_F64(PhysPt addr,Bitu store_to) {
|
|
|
|
fpu.regs[store_to].l.lower = mem_readd(addr);
|
|
|
|
fpu.regs[store_to].l.upper = mem_readd(addr+4);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FLD_F80(PhysPt addr) {
|
|
|
|
fpu.regs[TOP].d = FPU_FLD80(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FLD_I16(PhysPt addr,Bitu store_to) {
|
|
|
|
Bit16s blah = mem_readw(addr);
|
|
|
|
fpu.regs[store_to].d = static_cast<Real64>(blah);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FLD_I32(PhysPt addr,Bitu store_to) {
|
|
|
|
Bit32s blah = mem_readd(addr);
|
|
|
|
fpu.regs[store_to].d = static_cast<Real64>(blah);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FLD_I64(PhysPt addr,Bitu store_to) {
|
|
|
|
FPU_Reg blah;
|
|
|
|
blah.l.lower = mem_readd(addr);
|
|
|
|
blah.l.upper = mem_readd(addr+4);
|
|
|
|
fpu.regs[store_to].d = static_cast<Real64>(blah.ll);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FBLD(PhysPt addr,Bitu store_to) {
|
|
|
|
Bit64u val = 0;
|
|
|
|
Bitu in = 0;
|
|
|
|
Bit64u base = 1;
|
|
|
|
for(Bitu i = 0;i < 9;i++){
|
|
|
|
in = mem_readb(addr + i);
|
|
|
|
val += ( (in&0xf) * base); //in&0xf shouldn't be higher then 9
|
|
|
|
base *= 10;
|
|
|
|
val += ((( in>>4)&0xf) * base);
|
|
|
|
base *= 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
//last number, only now convert to float in order to get
|
|
|
|
//the best signification
|
|
|
|
Real64 temp = static_cast<Real64>(val);
|
|
|
|
in = mem_readb(addr + 9);
|
|
|
|
temp += ( (in&0xf) * base );
|
|
|
|
if(in&0x80) temp *= -1.0;
|
|
|
|
fpu.regs[store_to].d = temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FST_F32(PhysPt addr) {
|
|
|
|
union {
|
|
|
|
float f;
|
|
|
|
Bit32u l;
|
|
|
|
} blah;
|
|
|
|
//should depend on rounding method
|
|
|
|
blah.f = static_cast<float>(fpu.regs[TOP].d);
|
|
|
|
mem_writed(addr,blah.l);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FST_F64(PhysPt addr) {
|
|
|
|
mem_writed(addr,fpu.regs[TOP].l.lower);
|
|
|
|
mem_writed(addr+4,fpu.regs[TOP].l.upper);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FST_F80(PhysPt addr) {
|
|
|
|
FPU_ST80(addr,TOP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FST_I16(PhysPt addr) {
|
|
|
|
mem_writew(addr,static_cast<Bit16s>(FROUND(fpu.regs[TOP].d)));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FST_I32(PhysPt addr) {
|
|
|
|
mem_writed(addr,static_cast<Bit32s>(FROUND(fpu.regs[TOP].d)));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FST_I64(PhysPt addr) {
|
|
|
|
FPU_Reg blah;
|
|
|
|
blah.ll = static_cast<Bit64s>(FROUND(fpu.regs[TOP].d));
|
|
|
|
mem_writed(addr,blah.l.lower);
|
|
|
|
mem_writed(addr+4,blah.l.upper);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FBST(PhysPt addr) {
|
|
|
|
FPU_Reg val = fpu.regs[TOP];
|
|
|
|
bool sign = false;
|
|
|
|
if(val.d<0.0){ //sign
|
|
|
|
sign=true;
|
|
|
|
val.d=-val.d;
|
|
|
|
}
|
|
|
|
//numbers from back to front
|
|
|
|
Real64 temp=val.d;
|
|
|
|
Bitu p;
|
|
|
|
for(Bitu i=0;i<9;i++){
|
|
|
|
val.d=temp;
|
|
|
|
temp = static_cast<Real64>(static_cast<Bit64s>(floor(val.d/10.0)));
|
|
|
|
p = static_cast<Bitu>(val.d - 10.0*temp);
|
|
|
|
val.d=temp;
|
|
|
|
temp = static_cast<Real64>(static_cast<Bit64s>(floor(val.d/10.0)));
|
|
|
|
p |= (static_cast<Bitu>(val.d - 10.0*temp)<<4);
|
|
|
|
|
|
|
|
mem_writeb(addr+i,p);
|
|
|
|
}
|
|
|
|
val.d=temp;
|
|
|
|
temp = static_cast<Real64>(static_cast<Bit64s>(floor(val.d/10.0)));
|
|
|
|
p = static_cast<Bitu>(val.d - 10.0*temp);
|
|
|
|
if(sign)
|
|
|
|
p|=0x80;
|
|
|
|
mem_writeb(addr+9,p);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
static void FPU_FADD(Bitu op1, Bitu op2){
|
|
|
|
fpu.regs[op1].d+=fpu.regs[op2].d;
|
|
|
|
//flags and such :)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FSIN(void){
|
|
|
|
fpu.regs[TOP].d = sin(fpu.regs[TOP].d);
|
|
|
|
FPU_SET_C2(0);
|
|
|
|
//flags and such :)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FSINCOS(void){
|
|
|
|
Real64 temp = fpu.regs[TOP].d;
|
|
|
|
fpu.regs[TOP].d = sin(temp);
|
|
|
|
FPU_PUSH(cos(temp));
|
|
|
|
FPU_SET_C2(0);
|
|
|
|
//flags and such :)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FCOS(void){
|
|
|
|
fpu.regs[TOP].d = cos(fpu.regs[TOP].d);
|
|
|
|
FPU_SET_C2(0);
|
|
|
|
//flags and such :)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FSQRT(void){
|
|
|
|
fpu.regs[TOP].d = sqrt(fpu.regs[TOP].d);
|
|
|
|
//flags and such :)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
static void FPU_FPATAN(void){
|
2009-05-03 00:18:08 +02:00
|
|
|
fpu.regs[STV(1)].d = atan2(fpu.regs[STV(1)].d,fpu.regs[TOP].d);
|
2009-05-02 23:43:00 +02:00
|
|
|
FPU_FPOP();
|
|
|
|
//flags and such :)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
static void FPU_FPTAN(void){
|
|
|
|
fpu.regs[TOP].d = tan(fpu.regs[TOP].d);
|
|
|
|
FPU_PUSH(1.0);
|
|
|
|
FPU_SET_C2(0);
|
|
|
|
//flags and such :)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
static void FPU_FDIV(Bitu st, Bitu other){
|
|
|
|
fpu.regs[st].d= fpu.regs[st].d/fpu.regs[other].d;
|
|
|
|
//flags and such :)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FDIVR(Bitu st, Bitu other){
|
|
|
|
fpu.regs[st].d= fpu.regs[other].d/fpu.regs[st].d;
|
|
|
|
// flags and such :)
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void FPU_FMUL(Bitu st, Bitu other){
|
|
|
|
fpu.regs[st].d*=fpu.regs[other].d;
|
|
|
|
//flags and such :)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FSUB(Bitu st, Bitu other){
|
|
|
|
fpu.regs[st].d = fpu.regs[st].d - fpu.regs[other].d;
|
|
|
|
//flags and such :)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FSUBR(Bitu st, Bitu other){
|
|
|
|
fpu.regs[st].d= fpu.regs[other].d - fpu.regs[st].d;
|
|
|
|
//flags and such :)
|
|
|
|
return;
|
2009-05-02 23:12:18 +02:00
|
|
|
}
|
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
static void FPU_FXCH(Bitu st, Bitu other){
|
|
|
|
FPU_Tag tag = fpu.tags[other];
|
|
|
|
FPU_Reg reg = fpu.regs[other];
|
|
|
|
fpu.tags[other] = fpu.tags[st];
|
|
|
|
fpu.regs[other] = fpu.regs[st];
|
|
|
|
fpu.tags[st] = tag;
|
|
|
|
fpu.regs[st] = reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FST(Bitu st, Bitu other){
|
|
|
|
fpu.tags[other] = fpu.tags[st];
|
|
|
|
fpu.regs[other] = fpu.regs[st];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void FPU_FCOM(Bitu st, Bitu other){
|
2009-05-03 00:18:08 +02:00
|
|
|
if(((fpu.tags[st] != TAG_Valid) && (fpu.tags[st] != TAG_Zero)) ||
|
|
|
|
((fpu.tags[other] != TAG_Valid) && (fpu.tags[other] != TAG_Zero))){
|
2009-05-02 23:43:00 +02:00
|
|
|
FPU_SET_C3(1);FPU_SET_C2(1);FPU_SET_C0(1);return;
|
|
|
|
}
|
|
|
|
if(fpu.regs[st].d == fpu.regs[other].d){
|
|
|
|
FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(0);return;
|
|
|
|
}
|
|
|
|
if(fpu.regs[st].d < fpu.regs[other].d){
|
|
|
|
FPU_SET_C3(0);FPU_SET_C2(0);FPU_SET_C0(1);return;
|
|
|
|
}
|
|
|
|
// st > other
|
|
|
|
FPU_SET_C3(0);FPU_SET_C2(0);FPU_SET_C0(0);return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FUCOM(Bitu st, Bitu other){
|
|
|
|
//does atm the same as fcom
|
|
|
|
FPU_FCOM(st,other);
|
|
|
|
}
|
|
|
|
|
2009-05-03 00:18:08 +02:00
|
|
|
static void FPU_FRNDINT(void){
|
|
|
|
Bit64s temp= static_cast<Bit64s>(FROUND(fpu.regs[TOP].d));
|
|
|
|
fpu.regs[TOP].d=static_cast<double>(temp);
|
2009-05-02 23:43:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FPREM(void){
|
|
|
|
Real64 valtop = fpu.regs[TOP].d;
|
2009-05-03 00:18:08 +02:00
|
|
|
Real64 valdiv = fpu.regs[STV(1)].d;
|
2009-05-02 23:53:27 +02:00
|
|
|
Bit64s ressaved = static_cast<Bit64s>( (valtop/valdiv) );
|
|
|
|
// Some backups
|
|
|
|
// Real64 res=valtop - ressaved*valdiv;
|
|
|
|
// res= fmod(valtop,valdiv);
|
|
|
|
fpu.regs[TOP].d = valtop - ressaved*valdiv;
|
2009-05-02 23:43:00 +02:00
|
|
|
FPU_SET_C0(static_cast<Bitu>(ressaved&4));
|
|
|
|
FPU_SET_C3(static_cast<Bitu>(ressaved&2));
|
|
|
|
FPU_SET_C1(static_cast<Bitu>(ressaved&1));
|
|
|
|
FPU_SET_C2(0);
|
|
|
|
}
|
|
|
|
|
2009-05-03 00:18:08 +02:00
|
|
|
static void FPU_FPREM1(void){
|
|
|
|
Real64 valtop = fpu.regs[TOP].d;
|
|
|
|
Real64 valdiv = fpu.regs[STV(1)].d;
|
|
|
|
double quot = valtop/valdiv;
|
|
|
|
double quotf = floor(quot);
|
|
|
|
Bit64s ressaved;
|
|
|
|
if (quot-quotf>0.5) ressaved = static_cast<Bit64s>(quotf+1);
|
|
|
|
else if (quot-quotf<0.5) ressaved = static_cast<Bit64s>(quotf);
|
|
|
|
else ressaved = static_cast<Bit64s>((((static_cast<Bit64s>(quotf))&1)!=0)?(quotf+1):(quotf));
|
|
|
|
fpu.regs[TOP].d = valtop - ressaved*valdiv;
|
|
|
|
FPU_SET_C0(static_cast<Bitu>(ressaved&4));
|
|
|
|
FPU_SET_C3(static_cast<Bitu>(ressaved&2));
|
|
|
|
FPU_SET_C1(static_cast<Bitu>(ressaved&1));
|
|
|
|
FPU_SET_C2(0);
|
|
|
|
}
|
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
static void FPU_FXAM(void){
|
|
|
|
if(fpu.regs[TOP].ll & LONGTYPE(0x8000000000000000)) //sign
|
|
|
|
{
|
|
|
|
FPU_SET_C1(1);
|
2009-05-03 00:18:08 +02:00
|
|
|
}
|
|
|
|
else
|
2009-05-02 23:43:00 +02:00
|
|
|
{
|
|
|
|
FPU_SET_C1(0);
|
|
|
|
}
|
2009-05-03 00:18:08 +02:00
|
|
|
if(fpu.tags[TOP] == TAG_Empty)
|
|
|
|
{
|
|
|
|
FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(1);
|
|
|
|
return;
|
|
|
|
}
|
2009-05-02 23:43:00 +02:00
|
|
|
if(fpu.regs[TOP].d == 0.0) //zero or normalized number.
|
|
|
|
{
|
|
|
|
FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(0);
|
|
|
|
}
|
2009-05-03 00:18:08 +02:00
|
|
|
else
|
|
|
|
{
|
2009-05-02 23:43:00 +02:00
|
|
|
FPU_SET_C3(0);FPU_SET_C2(1);FPU_SET_C0(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-02 23:12:18 +02:00
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
static void FPU_F2XM1(void){
|
2009-05-03 00:18:08 +02:00
|
|
|
fpu.regs[TOP].d = pow(2.0,fpu.regs[TOP].d) - 1;
|
2009-05-02 23:43:00 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-05-02 23:53:27 +02:00
|
|
|
static void FPU_FYL2X(void){
|
2009-05-03 00:18:08 +02:00
|
|
|
fpu.regs[STV(1)].d*=log(fpu.regs[TOP].d)/log(static_cast<Real64>(2.0));
|
2009-05-02 23:43:00 +02:00
|
|
|
FPU_FPOP();
|
|
|
|
return;
|
|
|
|
}
|
2009-05-03 00:18:08 +02:00
|
|
|
|
|
|
|
static void FPU_FYL2XP1(void){
|
|
|
|
fpu.regs[STV(1)].d*=log(fpu.regs[TOP].d+1.0)/log(static_cast<Real64>(2.0));
|
|
|
|
FPU_FPOP();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-05-02 23:43:00 +02:00
|
|
|
static void FPU_FSCALE(void){
|
2009-05-03 00:18:08 +02:00
|
|
|
fpu.regs[TOP].d *= pow(2.0,static_cast<Real64>(static_cast<Bit64s>(fpu.regs[STV(1)].d)));
|
2009-05-02 23:43:00 +02:00
|
|
|
return; //2^x where x is chopped.
|
|
|
|
}
|
2009-05-02 23:12:18 +02:00
|
|
|
|
2009-05-03 00:02:15 +02:00
|
|
|
static void FPU_FSTENV(PhysPt addr){
|
2009-05-03 00:18:08 +02:00
|
|
|
FPU_SET_TOP(TOP);
|
2009-05-03 00:02:15 +02:00
|
|
|
if(!cpu.code.big) {
|
|
|
|
mem_writew(addr+0,static_cast<Bit16u>(fpu.cw));
|
|
|
|
mem_writew(addr+2,static_cast<Bit16u>(fpu.sw));
|
|
|
|
mem_writew(addr+4,static_cast<Bit16u>(FPU_GetTag()));
|
|
|
|
} else {
|
|
|
|
mem_writed(addr+0,static_cast<Bit32u>(fpu.cw));
|
|
|
|
mem_writed(addr+4,static_cast<Bit32u>(fpu.sw));
|
|
|
|
mem_writed(addr+8,static_cast<Bit32u>(FPU_GetTag()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FLDENV(PhysPt addr){
|
|
|
|
Bit16u tag;
|
|
|
|
Bit32u tagbig;
|
|
|
|
Bitu cw;
|
|
|
|
if(!cpu.code.big) {
|
|
|
|
cw = mem_readw(addr+0);
|
|
|
|
fpu.sw = mem_readw(addr+2);
|
|
|
|
tag = mem_readw(addr+4);
|
|
|
|
} else {
|
|
|
|
cw = mem_readd(addr+0);
|
2009-05-03 00:18:08 +02:00
|
|
|
fpu.sw = (Bit16u)mem_readd(addr+4);
|
2009-05-03 00:02:15 +02:00
|
|
|
tagbig = mem_readd(addr+8);
|
|
|
|
tag = static_cast<Bit16u>(tagbig);
|
|
|
|
}
|
|
|
|
FPU_SetTag(tag);
|
|
|
|
FPU_SetCW(cw);
|
2009-05-03 00:18:08 +02:00
|
|
|
TOP = FPU_GET_TOP();
|
2009-05-03 00:02:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FSAVE(PhysPt addr){
|
|
|
|
FPU_FSTENV(addr);
|
2009-05-03 00:18:08 +02:00
|
|
|
Bitu start = (cpu.code.big?28:14);
|
|
|
|
for(Bitu i = 0;i < 8;i++){
|
|
|
|
FPU_ST80(addr+start,STV(i));
|
|
|
|
start += 10;
|
2009-05-03 00:02:15 +02:00
|
|
|
}
|
2009-05-03 00:18:08 +02:00
|
|
|
FPU_FINIT();
|
2009-05-03 00:02:15 +02:00
|
|
|
}
|
|
|
|
|
2009-05-03 00:18:08 +02:00
|
|
|
static void FPU_FRSTOR(PhysPt addr){
|
2009-05-03 00:02:15 +02:00
|
|
|
FPU_FLDENV(addr);
|
2009-05-03 00:18:08 +02:00
|
|
|
Bitu start = (cpu.code.big?28:14);
|
|
|
|
for(Bitu i = 0;i < 8;i++){
|
|
|
|
fpu.regs[STV(i)].d = FPU_FLD80(addr+start);
|
|
|
|
start += 10;
|
2009-05-03 00:02:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-03 00:08:43 +02:00
|
|
|
static void FPU_FXTRACT(void) {
|
|
|
|
// function stores real bias in st and
|
|
|
|
// pushes the significant number onto the stack
|
|
|
|
// if double ever uses a different base please correct this function
|
|
|
|
|
|
|
|
FPU_Reg test = fpu.regs[TOP];
|
|
|
|
Bit64s exp80 = test.ll&LONGTYPE(0x7ff0000000000000);
|
|
|
|
Bit64s exp80final = (exp80>>52) - BIAS64;
|
|
|
|
Real64 mant = test.d / (pow(2.0,static_cast<Real64>(exp80final)));
|
2009-05-03 00:18:08 +02:00
|
|
|
fpu.regs[TOP].d = static_cast<Real64>(exp80final);
|
2009-05-03 00:08:43 +02:00
|
|
|
FPU_PUSH(mant);
|
|
|
|
}
|
2009-05-03 00:18:08 +02:00
|
|
|
|
|
|
|
static void FPU_FCHS(void){
|
|
|
|
fpu.regs[TOP].d = -1.0*(fpu.regs[TOP].d);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FABS(void){
|
|
|
|
fpu.regs[TOP].d = fabs(fpu.regs[TOP].d);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FTST(void){
|
|
|
|
fpu.regs[8].d = 0.0;
|
|
|
|
FPU_FCOM(TOP,8);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FLD1(void){
|
|
|
|
FPU_PREP_PUSH();
|
|
|
|
fpu.regs[TOP].d = 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FLDL2T(void){
|
|
|
|
FPU_PREP_PUSH();
|
|
|
|
fpu.regs[TOP].d = L2T;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FLDL2E(void){
|
|
|
|
FPU_PREP_PUSH();
|
|
|
|
fpu.regs[TOP].d = L2E;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FLDPI(void){
|
|
|
|
FPU_PREP_PUSH();
|
|
|
|
fpu.regs[TOP].d = PI;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FLDLG2(void){
|
|
|
|
FPU_PREP_PUSH();
|
|
|
|
fpu.regs[TOP].d = LG2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FLDLN2(void){
|
|
|
|
FPU_PREP_PUSH();
|
|
|
|
fpu.regs[TOP].d = LN2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FPU_FLDZ(void){
|
|
|
|
FPU_PREP_PUSH();
|
|
|
|
fpu.regs[TOP].d = 0.0;
|
|
|
|
fpu.tags[TOP] = TAG_Zero;
|
|
|
|
}
|