diff --git a/src/fpu/fpu.cpp b/src/fpu/fpu.cpp index af40c670..361af493 100644 --- a/src/fpu/fpu.cpp +++ b/src/fpu/fpu.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 The DOSBox Team + * Copyright (C) 2002-2003 The DOSBox Team * * 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 @@ -50,9 +50,13 @@ struct { INLINE void FPU_SetCW(Bitu word) { fpu.cw = word; - fpu.round = (FPU_Round)((word >> 8) & 3); + fpu.round = (FPU_Round)((word >> 10) & 3); + // word >>8 &3 is precission fpu.ex_mask = word & 0x3f; } + + + INLINE Bitu FPU_GET_TOP(void){ return (fpu.sw & 0x3800)>>11; } @@ -62,11 +66,39 @@ INLINE void FPU_SET_TOP(Bitu val){ return; } +INLINE void FPU_SET_C0(Bitu C){ + fpu.sw &= ~0x0100; + if(C) fpu.sw |= 0x0100; +} +INLINE void FPU_SET_C1(Bitu C){ + fpu.sw &= ~0x0200; + if(C) fpu.sw |= 0x0200; +} +INLINE void FPU_SET_C2(Bitu C){ + fpu.sw &= ~0x0400; + if(C) fpu.sw |= 0x0400; +} +INLINE void FPU_SET_C3(Bitu C){ + fpu.sw &= ~0x4000; + if(C) fpu.sw |= 0x4000; +} + +INLINE Bitu FPU_GET_C0(void){ + return (fpu.sw & 0x0100)>>8; +} +INLINE Bitu FPU_GET_C1(void){ + return (fpu.sw & 0x0200)>>9; +} +INLINE Bitu FPU_GET_C2(void){ + return (fpu.sw & 0x0400)>>10; +} +INLINE Bitu FPU_GET_C3(void){ + return (fpu.sw & 0x4000)>>14; +} #include "fpu_instructions.h" -/* TODO : MAKE REGULAR TREE A DEFINE or a function - : ESC6normal => esc4normal+pop or a define as well +/* TODO : ESC6normal => esc4normal+pop or a define as well : Make a smarter top system. won't matter that much in speed though. : #define ST fpu.top #define ST(i) (fpu.top+(i))&7 maybe*/ @@ -82,8 +114,11 @@ static void EATREE(Bitu _rm){ FPU_FMUL(top, 8); break; case 0x02: /* FICOM */ + FPU_FCOM(top,8); + break; case 0x03: /* FICOMP */ - LOG(LOG_FPU,LOG_WARN)("ESC EATREE:Unhandled group %d",group); + FPU_FCOM(top,8); + FPU_FPOP(); break; case 0x04: /* FISUB */ FPU_FSUB(top,8); @@ -105,11 +140,11 @@ static void EATREE(Bitu _rm){ void FPU_ESC0_EA(Bitu rm,PhysPt addr) { /* REGULAR TREE WITH 32 BITS REALS ? float ? */ //THIS SHOULD GO ALLRIGHT !?! - LOG(LOG_FPU, LOG_WARN)("ESC 0 EA used (check the result!)"); +// LOG(LOG_FPU, LOG_WARN)("ESC 0 EA used (check the result!)"); union { float f; - Bit32s l; + Bit32u l; } blah; blah.l = mem_readd(addr); fpu.regs[8].d = static_cast(blah.f); @@ -128,8 +163,11 @@ void FPU_ESC0_Normal(Bitu rm) { FPU_FMUL(top,(top+sub)&7); break; case 0x02: /* FCOM STi */ + FPU_FCOM(top,(top+sub)&7); + break; case 0x03: /* FCOMP STi */ - LOG(LOG_FPU,LOG_WARN)("ESC 0:Unhandled group %d subfunction %d",group,sub); + FPU_FCOM(top,(top+sub)&7); + FPU_FPOP(); break; case 0x04: /* FSUB ST,STi */ FPU_FSUB(top,(top+sub)&7); @@ -150,9 +188,61 @@ void FPU_ESC0_Normal(Bitu rm) { } void FPU_ESC1_EA(Bitu rm,PhysPt addr) { +// floats Bitu group=(rm >> 3) & 7; Bitu sub=(rm & 7); - LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); + switch(group){ + case 0x00: /* FLD */ + { + union { + float f; + Bit32u l; + } blah; + blah.l = mem_readd(addr); + FPU_PUSH(static_cast(blah.f)); + } + break; + + case 0x01: /* UNKNOWN */ + LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); + break; + case 0x02: /* FST */ + { + union { + float f; + Bit32u l; + } blah; + //should depend on rounding method + blah.f = static_cast(fpu.regs[FPU_GET_TOP()].d); + mem_writed(addr,blah.l); + } + break; + + case 0x03: /* FSTP */ + { + union { + float f; + Bit32u l; + } blah; + blah.f = static_cast(fpu.regs[FPU_GET_TOP()].d); + mem_writed(addr,blah.l); + } + FPU_FPOP(); + break; + case 0x05: /*FLDCW */ + { + Bit16u temp =mem_readw(addr); + FPU_SetCW(temp); + } + break; + case 0x07: /* FNSTCW*/ + mem_writew(addr,fpu.cw); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); + break; + } + } void FPU_ESC1_Normal(Bitu rm) { @@ -165,13 +255,36 @@ void FPU_ESC1_Normal(Bitu rm) { FPU_PUSH(fpu.regs[(top+sub)&7].d); } break; + case 0x01: /* FXCH STi */ + { + Bitu top = FPU_GET_TOP(); + FPU_FXCH(top,(top+sub)&7); + } + break; case 0x04: switch(sub){ case 0x00: /* FCHS */ + { + Bitu top = FPU_GET_TOP(); + fpu.regs[top].d = -1.0*(fpu.regs[top].d); + } + break; case 0x01: /* FABS */ + { + Bitu top = FPU_GET_TOP(); + fpu.regs[top].d = fabs(fpu.regs[top].d); + } + break; case 0x02: /* UNKNOWN */ case 0x03: /* ILLEGAL */ + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); + break; case 0x04: /* FTST */ + { Bitu top = FPU_GET_TOP(); + fpu.regs[8].d=0.0; + FPU_FCOM(top,8); + } + break; case 0x05: /* FXAM */ case 0x06: /* FTSTP (cyrix)*/ case 0x07: /* UNKNOWN */ @@ -203,15 +316,35 @@ void FPU_ESC1_Normal(Bitu rm) { } break; case 0x06: + switch(sub){ + case 0x02: /* FPTAN */ + FPU_FPTAN(); + break; + case 0x03: /* FPATAN */ + FPU_FPATAN(); + break; + default: LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); break; + } + break; case 0x07: switch(sub){ - + case 0x02: /* FSQRT */ + FPU_FSQRT(); + break; case 0x03: /* FSINCOS */ FPU_FSINCOS(); break; + case 0x04: /* FRNDINT */ + { + Bitu top = FPU_GET_TOP(); + Bit32s temp= static_cast(FROUND(fpu.regs[top].d)); + fpu.regs[top].d=static_cast(temp); + } + //TODO + break; case 0x06: /* FSIN */ FPU_FSIN(); break; @@ -246,6 +379,33 @@ void FPU_ESC2_Normal(Bitu rm) { void FPU_ESC3_EA(Bitu rm,PhysPt addr) { + Bitu group=(rm >> 3) & 7; + Bitu sub=(rm & 7); + switch(group){ + case 0x00: /* FLD */ + { + Bit32s blah = mem_readd(addr); + FPU_PUSH( static_cast(blah)); + } + break; + case 0x01: /* FISTTP */ + LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub); + break; + + case 0x02: /* FIST */ + { Bitu top = FPU_GET_TOP(); + mem_writed(addr,static_cast(FROUND(fpu.regs[top].d))); + } + break; + case 0x03: /*FISTP */ + { Bitu top = FPU_GET_TOP(); + mem_writed(addr,static_cast(FROUND(fpu.regs[top].d))); + FPU_FPOP(); + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub); + } } void FPU_ESC3_Normal(Bitu rm) { @@ -283,10 +443,9 @@ void FPU_ESC3_Normal(Bitu rm) { void FPU_ESC4_EA(Bitu rm,PhysPt addr) { /* REGULAR TREE WITH 64 BITS REALS ? double ? */ - E_Exit("how to load a double in esc 4 ea"); - //SEE ESC 0 EA -// double blah = mem_readd(addr); //wrong wrong wrong -// fpu.regs[8].d = static_cast(blah); +// E_Exit("how to load a double in esc 4 ea"); + fpu.regs[8].l.lower=mem_readd(addr); + fpu.regs[8].l.upper=mem_readd(addr+4); EATREE(rm); } @@ -302,9 +461,12 @@ void FPU_ESC4_Normal(Bitu rm) { case 0x01: /* FMULP STi,ST*/ FPU_FMUL((top+sub)&7,top); break; - case 0x02: /* FCOMP5*/ - case 0x03: /* weird*/ - LOG(LOG_FPU,LOG_WARN)("ESC 6:Unhandled group %d subfunction %d",group,sub); + case 0x02: /* FCOM*/ + FPU_FCOM(top,(top+sub)&7); + break; /* TODO IS THIS ALLRIGHT ????????? (maybe reverse operators) */ + case 0x03: /* FCOMP*/ + FPU_FCOM(top,(top+sub)&7); + FPU_FPOP(); break; case 0x04: /* FSUBRP STi,ST*/ FPU_FSUBR((top+sub)&7,top); @@ -323,17 +485,73 @@ void FPU_ESC4_Normal(Bitu rm) { } } - void FPU_ESC5_EA(Bitu rm,PhysPt addr) { Bitu group=(rm >> 3) & 7; Bitu sub=(rm & 7); - LOG(LOG_FPU,LOG_WARN)("ESC EA 5:Unhandled group %d subfunction %d",group,sub); + switch(group){ + case 0x00: /* FLD */ + { + FPU_Reg blah; + blah.l.lower=mem_readd(addr); + blah.l.upper=mem_readd(addr+4); + FPU_PUSH(blah.d); + } + break; + case 0x01: /* FISTTP */ + LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub); + break; + + case 0x02: /* FIST */ + { Bitu top = FPU_GET_TOP(); + mem_writed(addr,fpu.regs[top].l.lower); + mem_writed(addr+4,fpu.regs[top].l.upper); + } + break; + case 0x03: /*FISTP */ + { Bitu top = FPU_GET_TOP(); + mem_writed(addr,fpu.regs[top].l.lower); + mem_writed(addr+4,fpu.regs[top].l.upper); + FPU_FPOP(); + } + break; + case 0x07: /*FNSTSW NG DISAGREES ON THIS*/ + mem_writew(addr,fpu.sw); + //seems to break all dos4gw games :) + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub); + } } void FPU_ESC5_Normal(Bitu rm) { Bitu group=(rm >> 3) & 7; Bitu sub=(rm & 7); + Bitu top = FPU_GET_TOP(); + switch(group){ + case 0x00: /* FFREE STi */ + fpu.tags[(top+sub)&7]=TAG_Empty; + break; + case 0x01: /* FXCH STi*/ + FPU_FXCH(top,(top+sub)&7); + break; + case 0x02: /* FST STi */ + FPU_FST(top,(top+sub)&7); + break; + case 0x03: /* FSTP STi*/ + FPU_FST(top,(top+sub)&7); + FPU_FPOP(); + break; + case 0x04: /* FUCOM STi */ + FPU_FUCOM(top,(top+sub)&7); + break; + case 0x05: + FPU_FUCOM(top,(top+sub)&7); + FPU_FPOP(); + break; + default: LOG(LOG_FPU,LOG_WARN)("ESC 5:Unhandled group %d subfunction %d",group,sub); + break; + } } @@ -358,9 +576,15 @@ void FPU_ESC6_Normal(Bitu rm) { FPU_FMUL((top+sub)&7,top); break; case 0x02: /* FCOMP5*/ - case 0x03: /* weird*/ + FPU_FCOM(top,(top+sub)&7); + break; /* TODO IS THIS ALLRIGHT ????????? */ + case 0x03: /* weird*/ /*FCOMPP*/ + if(sub != 1){ LOG(LOG_FPU,LOG_WARN)("ESC 6:Unhandled group %d subfunction %d",group,sub); - // maybe return and don't pop + break; + } + FPU_FCOM(top,(top+sub)&7); + FPU_FPOP(); break; case 0x04: /* FSUBRP STi,ST*/ FPU_FSUBR((top+sub)&7,top); @@ -382,17 +606,34 @@ void FPU_ESC6_Normal(Bitu rm) { void FPU_ESC7_EA(Bitu rm,PhysPt addr) { + /* ROUNDING*/ + Bitu group=(rm >> 3) & 7; Bitu sub=(rm & 7); switch(group){ + case 0x00: /* FLD */ + { + Bit16s blah = mem_readw(addr); + FPU_PUSH( static_cast(blah)); + } + break; + case 0x01: /* FISTTP */ + LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub); + break; + + case 0x02: /* FIST */ + { Bitu top = FPU_GET_TOP(); + mem_writew(addr,static_cast(FROUND(fpu.regs[top].d))); + } + break; case 0x03: /*FISTP */ { Bitu top = FPU_GET_TOP(); - mem_writew(addr,static_cast(fpu.regs[top].d)); + mem_writew(addr,static_cast(FROUND(fpu.regs[top].d))); FPU_FPOP(); } break; default: - LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); + LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub); } } @@ -406,13 +647,15 @@ void FPU_ESC7_Normal(Bitu rm) { reg_ax = fpu.sw; break; default: + LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); break; } break; default: + LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); break; } - LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); + } diff --git a/src/fpu/fpu_instructions.h b/src/fpu/fpu_instructions.h index cf45b608..52d7e83e 100644 --- a/src/fpu/fpu_instructions.h +++ b/src/fpu/fpu_instructions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002 The DOSBox Team + * Copyright (C) 2002-2003 The DOSBox Team * * 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 @@ -17,8 +17,9 @@ */ + static void FPU_FINIT(void) { - FPU_SetCW(0x37); + FPU_SetCW(0x37F); fpu.sw=0; fpu.tags[0]=TAG_Empty; fpu.tags[1]=TAG_Empty; @@ -28,6 +29,7 @@ static void FPU_FINIT(void) { 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 } static void FPU_FCLEX(void){ fpu.sw&=0x7f00; //should clear exceptions @@ -70,6 +72,7 @@ static void FPU_FADD(Bitu op1, Bitu op2){ static void FPU_FSIN(void){ Bitu top = FPU_GET_TOP(); fpu.regs[top].d = sin(fpu.regs[top].d); + FPU_SET_C2(0); //flags and such :) return; } @@ -80,6 +83,7 @@ static void FPU_FSINCOS(void){ double temp = sin(fpu.regs[top].d); FPU_PUSH(cos(fpu.regs[top].d)); fpu.regs[top].d = temp; + FPU_SET_C2(0); //flags and such :) return; } @@ -87,10 +91,31 @@ static void FPU_FSINCOS(void){ static void FPU_FCOS(void){ Bitu top = FPU_GET_TOP(); fpu.regs[top].d = cos(fpu.regs[top].d); + FPU_SET_C2(0); //flags and such :) return; } +static void FPU_FSQRT(void){ + Bitu top = FPU_GET_TOP(); + fpu.regs[top].d = sqrt(fpu.regs[top].d); + //flags and such :) + return; +} +static void FPU_FPATAN(void){ + Bitu top = FPU_GET_TOP(); + fpu.regs[top].d = atan(fpu.regs[top].d); + FPU_SET_C2(0); + //flags and such :) + return; +} +static void FPU_FPTAN(void){ + Bitu top = FPU_GET_TOP(); + fpu.regs[top].d = tan(fpu.regs[top].d); + 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 :) @@ -119,4 +144,59 @@ static void FPU_FSUBR(Bitu st, Bitu other){ fpu.regs[st].d= fpu.regs[other].d - fpu.regs[st].d; //flags and such :) return; -} \ No newline at end of file +} + +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){ + if((fpu.tags[st] != TAG_Valid) || (fpu.tags[other] != TAG_Valid)){ + 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); +} + +static double FROUND(double in){ + switch(fpu.round){ + case ROUND_Nearest: + return((in-floor(in)>=0.5)?(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; + } +} diff --git a/src/fpu/fpu_types.h b/src/fpu/fpu_types.h index b7cb434b..33bc9e7b 100644 --- a/src/fpu/fpu_types.h +++ b/src/fpu/fpu_types.h @@ -32,10 +32,10 @@ enum FPU_Tag { enum FPU_Round { - ROUND_Nearest = 0, + ROUND_Nearest = 0, ROUND_Down = 1, - ROUND_Up = 2, + ROUND_Up = 2, ROUND_Chop = 3 }; //get pi from a real library -#define PI 3.1415926535 \ No newline at end of file +#define PI 3.14159265358979323846 \ No newline at end of file