DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
include/fpu.h
00001 /*
00002  *  Copyright (C) 2002-2013  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 #ifndef DOSBOX_FPU_H
00020 #define DOSBOX_FPU_H
00021 
00022 #ifndef DOSBOX_MEM_H
00023 #include "mem.h"
00024 #endif
00025 
00026 void FPU_ESC0_Normal(Bitu rm);
00027 void FPU_ESC0_EA(Bitu func,PhysPt ea);
00028 void FPU_ESC1_Normal(Bitu rm);
00029 void FPU_ESC1_EA(Bitu func,PhysPt ea);
00030 void FPU_ESC2_Normal(Bitu rm);
00031 void FPU_ESC2_EA(Bitu func,PhysPt ea);
00032 void FPU_ESC3_Normal(Bitu rm);
00033 void FPU_ESC3_EA(Bitu func,PhysPt ea);
00034 void FPU_ESC4_Normal(Bitu rm);
00035 void FPU_ESC4_EA(Bitu func,PhysPt ea);
00036 void FPU_ESC5_Normal(Bitu rm);
00037 void FPU_ESC5_EA(Bitu func,PhysPt ea);
00038 void FPU_ESC6_Normal(Bitu rm);
00039 void FPU_ESC6_EA(Bitu func,PhysPt ea);
00040 void FPU_ESC7_Normal(Bitu rm);
00041 void FPU_ESC7_EA(Bitu func,PhysPt ea);
00042 
00043 /* Floating point register, in the form the native host uses for "double".
00044  * This is slightly less precise than the 80-bit extended IEEE used by Intel,
00045  * but can be faster using the host processor "double" support. Most DOS games
00046  * using the FPU for 3D rendering are unaffected by the loss of precision.
00047  * However, there are cases where the full 80-bit precision is required such
00048  * as the "Fast Pentium memcpy trick" using the 80-bit versions of FLD/FST to
00049  * copy memory. */
00050 typedef union {
00051     double d;
00052 #ifndef WORDS_BIGENDIAN
00053     struct {
00054         Bit32u lower;
00055         Bit32s upper;
00056     } l;
00057 #else
00058     struct {
00059         Bit32s upper;
00060         Bit32u lower;
00061     } l;
00062 #endif
00063     Bit64s ll;
00064 } FPU_Reg;
00065 
00066 // dynamic x86 core needs this
00067 typedef struct {
00068     Bit32u m1;
00069     Bit32u m2;
00070     Bit16u m3;
00071 
00072     Bit16u d1;
00073     Bit32u d2;
00074 } FPU_P_Reg;
00075 
00076 // memory barrier macro. to ensure that reads/stores to one half of the FPU reg struct
00077 // do not overlap with reads/stores from the other half. things can go wrong if the
00078 // compiler writes code to write the mantissa, then load the overall as float, then store
00079 // the exponent. note this is not a hardware level memory barrier, this is a compiler
00080 // level memory barrier against the optimization engine.
00081 #if defined(__GCC__)
00082 # define FPU_Reg_m_barrier()    __asm__ __volatile__ ("":::"memory")
00083 #else
00084 # define FPU_Reg_m_barrier()
00085 #endif
00086 
00087 #pragma pack(push,1)
00088 typedef union {
00089 // TODO: The configure script needs to use "long double" on x86/x86_64 and verify sizeof(long double) == 10,
00090 //       else undef a macro to let the code emulate long double 80-bit IEEE. Also needs to determine host
00091 //       byte order here so host long double matches our struct.
00092         struct {
00093                 uint64_t        mantissa;               // [63:0]
00094                 unsigned int    exponent:15;            // [78:64]
00095                 unsigned int    sign:1;                 // [79:79]
00096         } f;
00097 #if defined(HAS_LONG_DOUBLE)
00098         long double             v;                      // [79:0]
00099 #endif
00100         struct {
00101                 uint64_t        l;
00102                 uint16_t        h;
00103         } raw;
00104 } FPU_Reg_80;
00105 // ^ Remember that in 80-bit extended, the mantissa contains both the fraction and integer bit. There is no
00106 //   "implied bit" like 32-bit and 64-bit formats.
00107 #pragma pack(pop)
00108 
00109 #define FPU_Reg_80_exponent_bias        (16383)
00110 
00111 #pragma pack(push,1)
00112 typedef union {
00113         struct {
00114                 uint64_t        mantissa:52;            // [51:0]
00115                 uint64_t        exponent:11;            // [62:52]
00116                 uint64_t        sign:1;                 // [63:63]
00117         } f;
00118         double                  v;
00119         uint64_t                raw;
00120 } FPU_Reg_64;
00121 #pragma pack(pop)
00122 
00123 #define FPU_Reg_64_exponent_bias        (1023)
00124 static const uint64_t FPU_Reg_64_implied_bit = ((uint64_t)1ULL << (uint64_t)52ULL);
00125 
00126 #pragma pack(push,1)
00127 typedef union {
00128         struct {
00129                 uint32_t        mantissa:23;            // [22:0]
00130                 uint32_t        exponent:8;             // [30:23]
00131                 uint32_t        sign:1;                 // [31:31]
00132         } f;
00133         float                   v;
00134         uint32_t                raw;
00135 } FPU_Reg_32;
00136 #pragma pack(pop)
00137 
00138 #define FPU_Reg_32_exponent_bias        (127)
00139 static const uint32_t FPU_Reg_32_implied_bit = ((uint32_t)1UL << (uint32_t)23UL);
00140 
00141 enum FPU_Tag {
00142         TAG_Valid = 0,
00143         TAG_Zero  = 1,
00144         TAG_Weird = 2,
00145         TAG_Empty = 3
00146 };
00147 
00148 enum FPU_Round {
00149         ROUND_Nearest = 0,              
00150         ROUND_Down    = 1,
00151         ROUND_Up      = 2,      
00152         ROUND_Chop    = 3
00153 };
00154 
00155 typedef struct {
00156         FPU_Reg         regs[9];
00157         FPU_Reg_80      regs_80[9];
00158         bool            use80[9];               // if set, use the 80-bit precision version
00159         FPU_Tag         tags[9];
00160         Bit16u          cw,cw_mask_all;
00161         Bit16u          sw;
00162         Bitu            top;
00163         FPU_Round       round;
00164 } FPU_rec;
00165 
00166 
00167 //get pi from a real library
00168 #define PI              3.14159265358979323846
00169 #define L2E             1.4426950408889634
00170 #define L2T             3.3219280948873623
00171 #define LN2             0.69314718055994531
00172 #define LG2             0.3010299956639812
00173 
00174 
00175 extern FPU_rec fpu;
00176 
00177 #define TOP fpu.top
00178 #define STV(i)  ( (fpu.top+ (i) ) & 7 )
00179 
00180 
00181 Bit16u FPU_GetTag(void);
00182 void FPU_FLDCW(PhysPt addr);
00183 
00184 static INLINE void FPU_SetTag(Bit16u tag){
00185         for(Bitu i=0;i<8;i++)
00186                 fpu.tags[i] = static_cast<FPU_Tag>((tag >>(2*i))&3);
00187 }
00188 
00189 static INLINE void FPU_SetCW(Bitu word){
00190         // HACK: Bits 13-15 are not defined. Apparently, one program likes to test for
00191         //       Cyrix EMC87 by trying to set bit 15. We want the test program to see
00192         //       us as an Intel 287 when cputype == 286.
00193         word &= 0x7FFF;
00194 
00195         fpu.cw = (Bit16u)word;
00196         fpu.cw_mask_all = (Bit16u)(word | 0x3f);
00197         fpu.round = (FPU_Round)((word >> 10) & 3);
00198 }
00199 
00200 
00201 static INLINE Bitu FPU_GET_TOP(void) {
00202         return (fpu.sw & 0x3800U) >> 11U;
00203 }
00204 
00205 static INLINE void FPU_SET_TOP(Bitu val){
00206         fpu.sw &= ~0x3800U;
00207         fpu.sw |= (val & 7U) << 11U;
00208 }
00209 
00210 
00211 static INLINE void FPU_SET_C0(Bitu C){
00212         fpu.sw &= ~0x0100U;
00213         if(C) fpu.sw |=  0x0100U;
00214 }
00215 
00216 static INLINE void FPU_SET_C1(Bitu C){
00217         fpu.sw &= ~0x0200U;
00218         if(C) fpu.sw |=  0x0200U;
00219 }
00220 
00221 static INLINE void FPU_SET_C2(Bitu C){
00222         fpu.sw &= ~0x0400U;
00223         if(C) fpu.sw |=  0x0400U;
00224 }
00225 
00226 static INLINE void FPU_SET_C3(Bitu C){
00227         fpu.sw &= ~0x4000U;
00228         if(C) fpu.sw |= 0x4000U;
00229 }
00230 
00231 static INLINE void FPU_SET_D(Bitu C){
00232         fpu.sw &= ~0x0002U;
00233         if(C) fpu.sw |= 0x0002U;
00234 }
00235 
00236 
00237 #endif