es40_float.h

Go to the documentation of this file.
00001 /* ES40 emulator.
00002  * Copyright (C) 2007-2008 by Camiel Vanderhoeven
00003  *
00004  * Website: www.camicom.com
00005  * E-mail : camiel@camicom.com
00006  * 
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  * 
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00020  * 
00021  * Although this is not required, the author would appreciate being notified of, 
00022  * and receiving any modifications you may make to the source code that might serve
00023  * the general public.
00024  */
00025 
00098 #include <math.h>
00099 
00100 //#define DEBUG_FP_CONVERSION 1
00101 //#define DEBUG_FP_LOADSTORE 1
00102 #define FLOAT_IS_IEEE 1
00103 
00108 inline double f2host(u64 val)
00109 {
00110   int s = (val & U64(0x8000000000000000)) ? 1 : 0;
00111   int e = (int) ((val & U64(0x7ff0000000000000)) >> 52);
00112   s64 f = (val & U64(0x000fffffffffffff));
00113   f |= U64(0x0010000000000000);
00114 
00115   double  res;
00116 
00117   if(e == 0)
00118     res = 0.0;
00119   else
00120     res = (s ? -1.0 : 1.0) * pow((double) 2.0, e - 1024) * ((double) f / (double) (s64) U64(0x0020000000000000));
00121 
00122 #if defined(DEBUG_FP_CONVERSION)
00123   printf("f/g->host: %016"LL "x -> %f   \n", val, res);
00124 #endif
00125   return res;
00126 }
00127 
00128 #define g2host  f2host
00129 
00134 inline double d2host(u64 val)
00135 {
00136   int s = (val & U64(0x8000000000000000)) ? 1 : 0;
00137   int e = (int) ((val & U64(0x7f80000000000000)) >> 55);
00138   s64 f = (val & U64(0x007fffffffffffff));
00139   f |= U64(0x0080000000000000);
00140 
00141   double  res;
00142 
00143   if(e == 0)
00144     res = 0.0;
00145   else
00146     res = (s ? -1.0 : 1.0) * pow((double) 2.0, e - 128) * ((double) f / (double) (s64) U64(0x0100000000000000));
00147 
00148 #if defined(DEBUG_FP_CONVERSION)
00149   printf("d->host: %016"LL "x -> %f   \n", val, res);
00150 #endif
00151   return res;
00152 }
00153 
00158 inline double s2host(u64 val)
00159 {
00160   double  res;
00161 
00162 #if defined(FLOAT_IS_IEEE)
00163   if(sizeof(double) == 8)
00164   {
00165     union s2h_conv
00166     {
00167       u64     a;
00168       double  b;
00169     } f_ieee;
00170     f_ieee.a = val;
00171     res = f_ieee.b;
00172   }
00173   else
00174 #endif
00175   {
00176     int s = (val & U64(0x8000000000000000)) ? 1 : 0;
00177     int e = (int) ((val & U64(0x7ff0000000000000)) >> 52);
00178     s64 f = (val & U64(0x000fffffffffffff));
00179 
00180     if(e == 2047)
00181     {
00182       if(f)
00183         res = (s ? -0.0 : 0.0) / 0.0; // NaN
00184       else
00185         res = (s ? -1.0 : 1.0) / 0.0; // +/- Inf
00186     }
00187     else if(e == 0)
00188     {
00189       if(f)
00190         res = (s ? -1.0 : 1.0) * ldexp((double) f / (double) ((s64) U64(0x10000000000000)),
00191                                                  -1022);
00192       else
00193         res = (s ? -1.0 : 1.0) * 0.0;
00194     }
00195     else
00196     {
00197       res = (s ? -1.0 : 1.0) * ldexp(1.0 + ((double) f / (double) ((s64) U64(0x0010000000000000))),
00198                                                  e - 1023);
00199     }
00200   }
00201 
00202 #if defined(DEBUG_FP_CONVERSION)
00203   printf("s/t->host: %016"LL "x -> %f   \n", val, res);
00204 #endif
00205   return res;
00206 }
00207 
00208 #define t2host  s2host
00209 
00213 inline bool i_isnan(u64 val)
00214 {
00215   int e = (int) ((val & U64(0x7ff0000000000000)) >> 52);
00216   s64 f = (val & U64(0x000fffffffffffff));
00217 
00218   return(e == 2047) && f;
00219 }
00220 
00225 inline u64 host2f(double val)
00226 {
00227   double  fr;
00228   double  v = val;
00229   int     s = (v < 0.0) ? 1 : 0;
00230   if(s)
00231     v *= -1.0;
00232 
00233   int   e = (int) (log((double) v) / log((double) 2.0));
00234   bool  exp_down = true;
00235 
00236   if(val == 0.0)
00237     return 0;
00238 
00239   fr = v / pow((double) 2.0, e);
00240 
00241   while((fr >= 1.0 && e < 127) || e < -127)
00242   {
00243     e++;
00244     exp_down = false;
00245     fr = v / pow((double) 2.0, e);
00246   }
00247 
00248   while(((fr < 0.5 && e > -127) || e > 127) && exp_down)
00249   {
00250     e--;
00251     fr = v / pow((double) 2.0, e);
00252   }
00253 
00254   e += 1024;
00255 
00256   u64 f = (u64) (fr * (double) U64(0x0020000000000000) + 0.5);
00257 
00258   f = (s ? U64(0x8000000000000000) : 0) | (((u64) e << 52) & U64(0x7ff0000000000000)) | (f & U64(0x000fffffe0000000));
00259 
00260 #if defined(DEBUG_FP_CONVERSION)
00261   printf("host->f: %f -> %016"LL "x   \n", val, f);
00262 #endif
00263   return f;
00264 }
00265 
00270 inline u64 host2g(double val)
00271 {
00272   double  fr;
00273   double  v = val;
00274   int     s = (v < 0.0) ? 1 : 0;
00275   if(s)
00276     v *= -1.0;
00277 
00278   int   e = (int) (log((double) v) / log((double) 2.0));
00279   bool  exp_down = true;
00280 
00281   if(val == 0.0)
00282     return 0;
00283 
00284   fr = v / pow((double) 2.0, e);
00285 
00286   while((fr >= 1.0 && e < 1023) || e < -1023)
00287   {
00288     e++;
00289     exp_down = false;
00290     fr = v / pow((double) 2.0, e);
00291   }
00292 
00293   while(((fr < 0.5 && e > -1023) || e > 1023) && exp_down)
00294   {
00295     e--;
00296     fr = v / pow((double) 2.0, e);
00297   }
00298 
00299   e += 1024;
00300 
00301   u64 f = (u64) (fr * (double) U64(0x0020000000000000) + 0.5);
00302 
00303   f = (s ? U64(0x8000000000000000) : 0) | (((u64) e << 52) & U64(0x7ff0000000000000)) | (f & U64(0x000fffffffffffff));
00304 
00305 #if defined(DEBUG_FP_CONVERSION)
00306   printf("host->g: %f -> %016"LL "x   \n", val, f);
00307 #endif
00308   return f;
00309 }
00310 
00315 inline u64 host2d(double val)
00316 {
00317   double  fr;
00318   double  v = val;
00319   int     s = (v < 0.0) ? 1 : 0;
00320   if(s)
00321     v *= -1.0;
00322 
00323   int   e = (int) (log((double) v) / log((double) 2.0));
00324   bool  exp_down = true;
00325 
00326   if(val == 0.0)
00327     return 0;
00328 
00329   fr = v / pow((double) 2.0, e);
00330 
00331   while((fr >= 1.0 && e < 127) || e < -127)
00332   {
00333     e++;
00334     exp_down = false;
00335     fr = v / pow((double) 2.0, e);
00336   }
00337 
00338   while(((fr < 0.5 && e > -127) || e > 127) && exp_down)
00339   {
00340     e--;
00341     fr = v / pow((double) 2.0, e);
00342   }
00343 
00344   e += 128;
00345 
00346   u64 f = (u64) (fr * (double) U64(0x0100000000000000) + 0.5);
00347 
00348   f = (s ? U64(0x8000000000000000) : 0) | (((u64) e << 55) & U64(0x7f80000000000000)) | (f & U64(0x007fffffffffffff));
00349 
00350 #if defined(DEBUG_FP_CONVERSION)
00351   printf("host->d: %f -> %016"LL "x   \n", val, f);
00352 #endif
00353   return f;
00354 }
00355 
00359 inline u32 map_s(u32 val)
00360 {
00361   if(val == 0)
00362     return 0;
00363   else if(val == 0xff)
00364     return 0x7ff;
00365   else if(val & 0x80)
00366     return(val & 0x7f) | 0x400;
00367   else
00368     return(val & 0x7f) | 0x380;
00369 }
00370 
00375 inline u64 host2s(double val)
00376 {
00377   u64 f;
00378   int s;
00379   int e;
00380 #if defined(FLOAT_IS_IEEE)
00381   if(sizeof(float) == 4)
00382   {
00383     union h2s_conv
00384     {
00385       u32   a;
00386       float b;
00387     } f_ieee;
00388     f_ieee.b = (float) val;
00389     s = (f_ieee.a >> 31) & 1;
00390     e = (f_ieee.a >> 23) & 0xff;
00391     f = (u64) (f_ieee.a >> 0 & 0x7fffff) << 29;
00392   }
00393   else
00394 #endif
00395   {
00396     double  v = val;
00397     s = (v < 0.0) ? 1 : 0;
00398     if(s)
00399       v *= -1.0;
00400     e = (int) (log((double) v) / log((double) 2.0));
00401 
00402     double  fr;
00403     bool    exp_down = true;
00404 
00405     if(val == 0.0)
00406       return 0;
00407 
00408     fr = v / pow((double) 2.0, e);
00409 
00410     while((fr >= 2.0 && e < 127) || e < -127)
00411     {
00412       e++;
00413       exp_down = false;
00414       fr = v / pow((double) 2.0, e);
00415     }
00416 
00417     while(((fr < 1.0 && e > -127) || e > 127) && exp_down)
00418     {
00419       e--;
00420       fr = v / pow((double) 2.0, e);
00421     }
00422 
00423     e += 255;
00424 
00425     if(e == 0)
00426       fr = v / pow((double) 2.0, -126);
00427 
00428     f = (u64) (fr * (double) U64(0x0010000000000000) + 0.5);
00429   }
00430 
00431   e = map_s(e);
00432 
00433   f = (s ? U64(0x800000000000000) : 0) | (((u64) e << 52) & U64(0x7ff0000000000000)) | (f & U64(0x000fffffe0000000));
00434 
00435 #if defined(DEBUG_FP_CONVERSION)
00436   printf("host->s: %f -> %016"LL "x   \n", val, f);
00437 #endif
00438   return f;
00439 }
00440 
00445 inline u64 host2t(double val)
00446 {
00447   u64 f;
00448 #if defined(FLOAT_IS_IEEE)
00449   if(sizeof(double) == 8)
00450   {
00451     union h2t_conv
00452     {
00453       u64     a;
00454       double  b;
00455     } f_ieee;
00456     f_ieee.b = val;
00457     f = f_ieee.a;
00458   }
00459   else
00460 #endif
00461   {
00462     double  v = val;
00463     int     s = (v < 0.0) ? 1 : 0;
00464     if(s)
00465       v *= -1.0;
00466 
00467     int     e = (int) (log((double) v) / log((double) 2.0));
00468     double  fr;
00469     bool    exp_down = true;
00470 
00471     if(val == 0.0)
00472       return 0;
00473 
00474     fr = v / pow((double) 2.0, e);
00475 
00476     while((fr >= 2.0 && e < 1023) || e < -1023)
00477     {
00478       e++;
00479       exp_down = false;
00480       fr = v / pow((double) 2.0, e);
00481     }
00482 
00483     while(((fr < 1.0 && e > -1023) || e > 1023) && exp_down)
00484     {
00485       e--;
00486       fr = v / pow((double) 2.0, e);
00487     }
00488 
00489     e += 1023;
00490 
00491     if(e == 0)
00492       fr = v / pow((double) 2.0, -1022);
00493 
00494     f = (u64) (fr * (double) U64(0x0010000000000000) + 0.5);
00495 
00496     f = (s ? U64(0x800000000000000) : 0) |
00497       (((u64) e << 52) & U64(0x7ff0000000000000)) |
00498         (f & U64(0x000fffffffffffff));
00499   }
00500 
00501 #if defined(DEBUG_FP_CONVERSION)
00502   printf("host->t: %f -> %016"LL "x   \n", val, f);
00503 #endif
00504   return f;
00505 }
00506 
00511 inline u32 store_f(u64 val)
00512 {
00513   u64 retval = (val & U64(0x00001fffe0000000)) >> 13; /* frac.lo          : 29..44 --> 16..31 */
00514   retval |= (val & U64(0xc000000000000000)) >> 48;    /* exp.hi + sign    : 62..63 --> 14..15 */
00515   retval |= (val & U64(0x07ffe00000000000)) >> 45;    /* frac.hi + exp.lo : 45..58 -->  0..13 */
00516 
00517 #if defined(DEBUG_FP_LOADSTORE)
00518   printf("f->mem: %016"LL "x -> %08x   \n", val, retval);
00519 #endif
00520   return(u32) retval;
00521 }
00522 
00527 inline u64 store_g(u64 val)
00528 {
00529   u64 retval = (val >> 48) & U64(0x000000000000ffff);
00530   retval |= (val >> 16) & U64(0x00000000ffff0000);
00531   retval |= (val << 48) & U64(0xffff000000000000);
00532   retval |= (val << 16) & U64(0x0000ffff00000000);
00533 
00534 #if defined(DEBUG_FP_LOADSTORE)
00535   printf("g->mem: %016"LL "x -> %016"LL "x   \n", val, retval);
00536 #endif
00537   return retval;
00538 }
00539 
00544 inline u64 load_f(u32 val)
00545 {
00546   u64 retval = (u64) (val & 0xffff0000) << 13;  /* frac.lo          : 16..31 --> 29..44 */
00547   retval |= (u64) (val & 0x0000c000) << 48;     /* exp.hi + sign    : 14..15 --> 62..63 */
00548   retval |= (u64) (val & 0x00003fff) << 45;     /* frac.hi + exp.lo :  0..13 --> 45..58 */
00549   if(((val & 0x00004000) == 0) && ((val & 0x00003f80) != 0))
00550     retval |= U64(0x3800000000000000);          /* exp.mid */
00551 
00552 #if defined(DEBUG_FP_LOADSTORE)
00553   printf("mem->f: %08x -> %016"LL "x   \n", val, retval);
00554 #endif
00555   return retval;
00556 }
00557 
00562 inline u64 itof_f(u64 val)
00563 {
00564   u64 retval = (val & U64(0x3fffffff)) << 29; /* frac + exp.lo  :  0..29 --> 29..58 */
00565   retval |= (val & U64(0xc0000000)) << 32;    /* exp.hi + sign : 30..31 --> 62..63 */
00566   if(((val & U64(0x40000000)) == 0) && ((val & U64(0x3f800000)) != 0))
00567     retval |= U64(0x3800000000000000);        /* exp.mid */
00568 
00569 #if defined(DEBUG_FP_LOADSTORE)
00570   printf("reg->f: %08x -> %016"LL "x   \n", val, retval);
00571 #endif
00572   return retval;
00573 }
00574 
00579 inline u64 load_g(u64 val)
00580 {
00581   u64 retval = (val & U64(0x000000000000ffff)) << 48;
00582   retval |= (val & U64(0x00000000ffff0000)) << 16;
00583   retval |= (val & U64(0x0000ffff00000000)) >> 16;
00584   retval |= (val & U64(0xffff000000000000)) >> 48;
00585 
00586 #if defined(DEBUG_FP_LOADSTORE)
00587   printf("mem->g: %016"LL "x -> %016"LL "x   \n", val, retval);
00588 #endif
00589   return retval;
00590 }
00591 
00596 inline u64 load_s(u32 val)
00597 {
00598   return((val & U64(0x80000000)) << 32)     // sign
00599   | ((u64) map_s((val >> 23) & 0xff) << 52) // exp
00600   | ((val & U64(0x7fffff)) << 29);
00601 }
00602 
00607 inline u32 store_s(u64 val)
00608 {
00609   return((u32) (val >> 32) & 0xc0000000) | ((u32) (val >> 29) & 0x3fffffff);
00610 }

SourceForge.net Logo
Project space on SourceForge.net