Path: blob/master/libmupen64plus/mupen64plus-core/src/r4300/fpu.h
2 views
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1* Mupen64plus - fpu.c *2* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *3* Copyright (C) 2010 Ari64 *4* *5* This program is free software; you can redistribute it and/or modify *6* it under the terms of the GNU General Public License as published by *7* the Free Software Foundation; either version 2 of the License, or *8* (at your option) any later version. *9* *10* This program is distributed in the hope that it will be useful, *11* but WITHOUT ANY WARRANTY; without even the implied warranty of *12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *13* GNU General Public License for more details. *14* *15* You should have received a copy of the GNU General Public License *16* along with this program; if not, write to the *17* Free Software Foundation, Inc., *18* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *19* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */2021#include <math.h>2223#include "r4300.h"2425#ifdef _MSC_VER26#define M64P_FPU_INLINE static __inline27#include <float.h>28typedef enum { FE_TONEAREST = 0, FE_TOWARDZERO, FE_UPWARD, FE_DOWNWARD } eRoundType;29static void fesetround(eRoundType RoundType)30{31static const unsigned int msRound[4] = { _RC_NEAR, _RC_CHOP, _RC_UP, _RC_DOWN };32unsigned int oldX87, oldSSE2;33__control87_2(msRound[RoundType], _MCW_RC, &oldX87, &oldSSE2);34}35static __inline double round(double x) { return floor(x + 0.5); }36static __inline float roundf(float x) { return (float) floor(x + 0.5); }37static __inline double trunc(double x) { return (double) (int) x; }38static __inline float truncf(float x) { return (float) (int) x; }39#define isnan _isnan40#else41#define M64P_FPU_INLINE static inline42#include <fenv.h>43#endif444546M64P_FPU_INLINE void set_rounding(void)47{48switch(rounding_mode) {49case 0x33F:50fesetround(FE_TONEAREST);51break;52case 0xF3F:53fesetround(FE_TOWARDZERO);54break;55case 0xB3F:56fesetround(FE_UPWARD);57break;58case 0x73F:59fesetround(FE_DOWNWARD);60break;61}62}6364M64P_FPU_INLINE void cvt_s_w(int *source,float *dest)65{66set_rounding();67*dest = (float) *source;68}69M64P_FPU_INLINE void cvt_d_w(int *source,double *dest)70{71set_rounding();72*dest = (double) *source;73}74M64P_FPU_INLINE void cvt_s_l(long long *source,float *dest)75{76set_rounding();77*dest = (float) *source;78}79M64P_FPU_INLINE void cvt_d_l(long long *source,double *dest)80{81set_rounding();82*dest = (double) *source;83}84M64P_FPU_INLINE void cvt_d_s(float *source,double *dest)85{86set_rounding();87*dest = (double) *source;88}89M64P_FPU_INLINE void cvt_s_d(double *source,float *dest)90{91set_rounding();92*dest = (float) *source;93}9495M64P_FPU_INLINE void round_l_s(float *source,long long *dest)96{97*dest = (long long) roundf(*source);98}99M64P_FPU_INLINE void round_w_s(float *source,int *dest)100{101*dest = (int) roundf(*source);102}103M64P_FPU_INLINE void trunc_l_s(float *source,long long *dest)104{105*dest = (long long) truncf(*source);106}107M64P_FPU_INLINE void trunc_w_s(float *source,int *dest)108{109*dest = (int) truncf(*source);110}111M64P_FPU_INLINE void ceil_l_s(float *source,long long *dest)112{113*dest = (long long) ceilf(*source);114}115M64P_FPU_INLINE void ceil_w_s(float *source,int *dest)116{117*dest = (int) ceilf(*source);118}119M64P_FPU_INLINE void floor_l_s(float *source,long long *dest)120{121*dest = (long long) floorf(*source);122}123M64P_FPU_INLINE void floor_w_s(float *source,int *dest)124{125*dest = (int) floorf(*source);126}127128M64P_FPU_INLINE void round_l_d(double *source,long long *dest)129{130*dest = (long long) round(*source);131}132M64P_FPU_INLINE void round_w_d(double *source,int *dest)133{134*dest = (int) round(*source);135}136M64P_FPU_INLINE void trunc_l_d(double *source,long long *dest)137{138*dest = (long long) trunc(*source);139}140M64P_FPU_INLINE void trunc_w_d(double *source,int *dest)141{142*dest = (int) trunc(*source);143}144M64P_FPU_INLINE void ceil_l_d(double *source,long long *dest)145{146*dest = (long long) ceil(*source);147}148M64P_FPU_INLINE void ceil_w_d(double *source,int *dest)149{150*dest = (int) ceil(*source);151}152M64P_FPU_INLINE void floor_l_d(double *source,long long *dest)153{154*dest = (long long) floor(*source);155}156M64P_FPU_INLINE void floor_w_d(double *source,int *dest)157{158*dest = (int) floor(*source);159}160161M64P_FPU_INLINE void cvt_w_s(float *source,int *dest)162{163set_rounding();164switch(FCR31&3)165{166case 0: round_w_s(source,dest);return;167case 1: trunc_w_s(source,dest);return;168case 2: ceil_w_s(source,dest);return;169case 3: floor_w_s(source,dest);return;170}171}172M64P_FPU_INLINE void cvt_w_d(double *source,int *dest)173{174set_rounding();175switch(FCR31&3)176{177case 0: round_w_d(source,dest);return;178case 1: trunc_w_d(source,dest);return;179case 2: ceil_w_d(source,dest);return;180case 3: floor_w_d(source,dest);return;181}182}183M64P_FPU_INLINE void cvt_l_s(float *source,long long *dest)184{185set_rounding();186switch(FCR31&3)187{188case 0: round_l_s(source,dest);return;189case 1: trunc_l_s(source,dest);return;190case 2: ceil_l_s(source,dest);return;191case 3: floor_l_s(source,dest);return;192}193}194M64P_FPU_INLINE void cvt_l_d(double *source,long long *dest)195{196set_rounding();197switch(FCR31&3)198{199case 0: round_l_d(source,dest);return;200case 1: trunc_l_d(source,dest);return;201case 2: ceil_l_d(source,dest);return;202case 3: floor_l_d(source,dest);return;203}204}205206M64P_FPU_INLINE void c_f_s()207{208FCR31 &= ~0x800000;209}210M64P_FPU_INLINE void c_un_s(float *source,float *target)211{212FCR31=(isnan(*source) || isnan(*target)) ? FCR31|0x800000 : FCR31&~0x800000;213}214215M64P_FPU_INLINE void c_eq_s(float *source,float *target)216{217if (isnan(*source) || isnan(*target)) {FCR31&=~0x800000;return;}218FCR31 = *source==*target ? FCR31|0x800000 : FCR31&~0x800000;219}220M64P_FPU_INLINE void c_ueq_s(float *source,float *target)221{222if (isnan(*source) || isnan(*target)) {FCR31|=0x800000;return;}223FCR31 = *source==*target ? FCR31|0x800000 : FCR31&~0x800000;224}225226M64P_FPU_INLINE void c_olt_s(float *source,float *target)227{228if (isnan(*source) || isnan(*target)) {FCR31&=~0x800000;return;}229FCR31 = *source<*target ? FCR31|0x800000 : FCR31&~0x800000;230}231M64P_FPU_INLINE void c_ult_s(float *source,float *target)232{233if (isnan(*source) || isnan(*target)) {FCR31|=0x800000;return;}234FCR31 = *source<*target ? FCR31|0x800000 : FCR31&~0x800000;235}236237M64P_FPU_INLINE void c_ole_s(float *source,float *target)238{239if (isnan(*source) || isnan(*target)) {FCR31&=~0x800000;return;}240FCR31 = *source<=*target ? FCR31|0x800000 : FCR31&~0x800000;241}242M64P_FPU_INLINE void c_ule_s(float *source,float *target)243{244if (isnan(*source) || isnan(*target)) {FCR31|=0x800000;return;}245FCR31 = *source<=*target ? FCR31|0x800000 : FCR31&~0x800000;246}247248M64P_FPU_INLINE void c_sf_s(float *source,float *target)249{250//if (isnan(*source) || isnan(*target)) // FIXME - exception251FCR31&=~0x800000;252}253M64P_FPU_INLINE void c_ngle_s(float *source,float *target)254{255//if (isnan(*source) || isnan(*target)) // FIXME - exception256FCR31&=~0x800000;257}258259M64P_FPU_INLINE void c_seq_s(float *source,float *target)260{261//if (isnan(*source) || isnan(*target)) // FIXME - exception262FCR31 = *source==*target ? FCR31|0x800000 : FCR31&~0x800000;263}264M64P_FPU_INLINE void c_ngl_s(float *source,float *target)265{266//if (isnan(*source) || isnan(*target)) // FIXME - exception267FCR31 = *source==*target ? FCR31|0x800000 : FCR31&~0x800000;268}269270M64P_FPU_INLINE void c_lt_s(float *source,float *target)271{272//if (isnan(*source) || isnan(*target)) // FIXME - exception273FCR31 = *source<*target ? FCR31|0x800000 : FCR31&~0x800000;274}275M64P_FPU_INLINE void c_nge_s(float *source,float *target)276{277//if (isnan(*source) || isnan(*target)) // FIXME - exception278FCR31 = *source<*target ? FCR31|0x800000 : FCR31&~0x800000;279}280281M64P_FPU_INLINE void c_le_s(float *source,float *target)282{283//if (isnan(*source) || isnan(*target)) // FIXME - exception284FCR31 = *source<=*target ? FCR31|0x800000 : FCR31&~0x800000;285}286M64P_FPU_INLINE void c_ngt_s(float *source,float *target)287{288//if (isnan(*source) || isnan(*target)) // FIXME - exception289FCR31 = *source<=*target ? FCR31|0x800000 : FCR31&~0x800000;290}291292M64P_FPU_INLINE void c_f_d()293{294FCR31 &= ~0x800000;295}296M64P_FPU_INLINE void c_un_d(double *source,double *target)297{298FCR31=(isnan(*source) || isnan(*target)) ? FCR31|0x800000 : FCR31&~0x800000;299}300301M64P_FPU_INLINE void c_eq_d(double *source,double *target)302{303if (isnan(*source) || isnan(*target)) {FCR31&=~0x800000;return;}304FCR31 = *source==*target ? FCR31|0x800000 : FCR31&~0x800000;305}306M64P_FPU_INLINE void c_ueq_d(double *source,double *target)307{308if (isnan(*source) || isnan(*target)) {FCR31|=0x800000;return;}309FCR31 = *source==*target ? FCR31|0x800000 : FCR31&~0x800000;310}311312M64P_FPU_INLINE void c_olt_d(double *source,double *target)313{314if (isnan(*source) || isnan(*target)) {FCR31&=~0x800000;return;}315FCR31 = *source<*target ? FCR31|0x800000 : FCR31&~0x800000;316}317M64P_FPU_INLINE void c_ult_d(double *source,double *target)318{319if (isnan(*source) || isnan(*target)) {FCR31|=0x800000;return;}320FCR31 = *source<*target ? FCR31|0x800000 : FCR31&~0x800000;321}322323M64P_FPU_INLINE void c_ole_d(double *source,double *target)324{325if (isnan(*source) || isnan(*target)) {FCR31&=~0x800000;return;}326FCR31 = *source<=*target ? FCR31|0x800000 : FCR31&~0x800000;327}328M64P_FPU_INLINE void c_ule_d(double *source,double *target)329{330if (isnan(*source) || isnan(*target)) {FCR31|=0x800000;return;}331FCR31 = *source<=*target ? FCR31|0x800000 : FCR31&~0x800000;332}333334M64P_FPU_INLINE void c_sf_d(double *source,double *target)335{336//if (isnan(*source) || isnan(*target)) // FIXME - exception337FCR31&=~0x800000;338}339M64P_FPU_INLINE void c_ngle_d(double *source,double *target)340{341//if (isnan(*source) || isnan(*target)) // FIXME - exception342FCR31&=~0x800000;343}344345M64P_FPU_INLINE void c_seq_d(double *source,double *target)346{347//if (isnan(*source) || isnan(*target)) // FIXME - exception348FCR31 = *source==*target ? FCR31|0x800000 : FCR31&~0x800000;349}350M64P_FPU_INLINE void c_ngl_d(double *source,double *target)351{352//if (isnan(*source) || isnan(*target)) // FIXME - exception353FCR31 = *source==*target ? FCR31|0x800000 : FCR31&~0x800000;354}355356M64P_FPU_INLINE void c_lt_d(double *source,double *target)357{358//if (isnan(*source) || isnan(*target)) // FIXME - exception359FCR31 = *source<*target ? FCR31|0x800000 : FCR31&~0x800000;360}361M64P_FPU_INLINE void c_nge_d(double *source,double *target)362{363//if (isnan(*source) || isnan(*target)) // FIXME - exception364FCR31 = *source<*target ? FCR31|0x800000 : FCR31&~0x800000;365}366367M64P_FPU_INLINE void c_le_d(double *source,double *target)368{369//if (isnan(*source) || isnan(*target)) // FIXME - exception370FCR31 = *source<=*target ? FCR31|0x800000 : FCR31&~0x800000;371}372M64P_FPU_INLINE void c_ngt_d(double *source,double *target)373{374//if (isnan(*source) || isnan(*target)) // FIXME - exception375FCR31 = *source<=*target ? FCR31|0x800000 : FCR31&~0x800000;376}377378379M64P_FPU_INLINE void add_s(float *source1,float *source2,float *target)380{381set_rounding();382*target=(*source1)+(*source2);383}384M64P_FPU_INLINE void sub_s(float *source1,float *source2,float *target)385{386set_rounding();387*target=(*source1)-(*source2);388}389M64P_FPU_INLINE void mul_s(float *source1,float *source2,float *target)390{391set_rounding();392*target=(*source1)*(*source2);393}394M64P_FPU_INLINE void div_s(float *source1,float *source2,float *target)395{396set_rounding();397*target=(*source1)/(*source2);398}399M64P_FPU_INLINE void sqrt_s(float *source,float *target)400{401set_rounding();402*target=sqrtf(*source);403}404M64P_FPU_INLINE void abs_s(float *source,float *target)405{406set_rounding();407*target=fabsf(*source);408}409M64P_FPU_INLINE void mov_s(float *source,float *target)410{411set_rounding();412*target=*source;413}414M64P_FPU_INLINE void neg_s(float *source,float *target)415{416set_rounding();417*target=-(*source);418}419M64P_FPU_INLINE void add_d(double *source1,double *source2,double *target)420{421set_rounding();422*target=(*source1)+(*source2);423}424M64P_FPU_INLINE void sub_d(double *source1,double *source2,double *target)425{426set_rounding();427*target=(*source1)-(*source2);428}429M64P_FPU_INLINE void mul_d(double *source1,double *source2,double *target)430{431set_rounding();432*target=(*source1)*(*source2);433}434M64P_FPU_INLINE void div_d(double *source1,double *source2,double *target)435{436set_rounding();437*target=(*source1)/(*source2);438}439M64P_FPU_INLINE void sqrt_d(double *source,double *target)440{441set_rounding();442*target=sqrt(*source);443}444M64P_FPU_INLINE void abs_d(double *source,double *target)445{446set_rounding();447*target=fabs(*source);448}449M64P_FPU_INLINE void mov_d(double *source,double *target)450{451set_rounding();452*target=*source;453}454M64P_FPU_INLINE void neg_d(double *source,double *target)455{456set_rounding();457*target=-(*source);458}459460461