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