fpu.C

Go to the documentation of this file.
00001 /*!@file Util/fpu.C manipulate floating-point unit (FPU) settings */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Rob Peters <rjpeters at usc dot edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Util/fpu.C $
00035 // $Id: fpu.C 11208 2009-05-20 02:03:21Z itti $
00036 //
00037 
00038 #ifndef UTIL_FPU_C_DEFINED
00039 #define UTIL_FPU_C_DEFINED
00040 
00041 #include "Util/fpu.H"
00042 
00043 #include "Util/StringConversions.H"
00044 #include "Util/log.H"
00045 
00046 #include <cstdio>
00047 
00048 namespace
00049 {
00050 #ifdef INVT_CPU_IX86
00051 
00052   const unsigned short infmask = (1<<12);
00053   const unsigned short roundmask = ((1<<11)|(1<<10));
00054   const unsigned short precmask = ((1<<9)|(1<<8));
00055   const unsigned short exceptmask = 0xff;
00056 
00057   /* Here's a table describing the 16-bit x87 floating-point control
00058      word register (from
00059      http://www.delorie.com/djgpp/doc/libc/libc_112.html)
00060 
00061      ---- ---- --XX XXXX = MCW_EM - exception masks (1=handle exception
00062                                                      internally, 0=fault)
00063      ---- ---- ---- ---X = EM_INVALID - invalid operation
00064      ---- ---- ---- --X- = EM_DENORMAL - denormal operand
00065      ---- ---- ---- -X-- = EM_ZERODIVIDE - divide by zero
00066      ---- ---- ---- X--- = EM_OVERFLOW - overflow
00067      ---- ---- ---X ---- = EM_UNDERFLOW - underflow
00068      ---- ---- --X- ---- = EM_INEXACT - rounding was required
00069      ---- --XX ---- ---- = MCW_PC - precision control
00070      ---- --00 ---- ---- = PC_24 - single precision
00071      ---- --10 ---- ---- = PC_53 - double precision
00072      ---- --11 ---- ---- = PC_64 - extended precision
00073      ---- XX-- ---- ---- = MCW_RC - rounding control
00074      ---- 00-- ---- ---- = RC_NEAR - round to nearest
00075      ---- 01-- ---- ---- = RC_DOWN - round towards -Inf
00076      ---- 10-- ---- ---- = RC_UP - round towards +Inf
00077      ---- 11-- ---- ---- = RC_CHOP - round towards zero
00078      ---X ---- ---- ---- = MCW_IC - infinity control (obsolete,
00079                                                       always affine)
00080      ---0 ---- ---- ---- = IC_AFFINE - -Inf < +Inf
00081      ---1 ---- ---- ---- = IC_PROJECTIVE - -Inf == +Inf
00082 
00083    */
00084 
00085   unsigned short get_x87_control_word()
00086   {
00087     volatile unsigned short ctrl;
00088 
00089     asm("fstcw %0"
00090         :"=m"(ctrl));
00091 
00092     return ctrl;
00093   }
00094 
00095   void set_x87_control_word(volatile unsigned short ctrl)
00096   {
00097     asm("fldcw %0\n\t"
00098         "fwait"
00099         :
00100         :"m"(ctrl));
00101   }
00102 
00103   void show_x87_control_word(unsigned short ctrl)
00104   {
00105     printf("control word:               0x%04x\n", int(ctrl));
00106     printf("     infinity-control bits: 0x%04x\n", int(ctrl & infmask));
00107     printf("     rounding-control bits: 0x%04x\n", int(ctrl & roundmask));
00108     printf("    precision-control bits: 0x%04x\n", int(ctrl & precmask));
00109     printf("           interrupt masks: 0x%04x\n", int(ctrl & exceptmask));
00110   }
00111 #endif
00112 }
00113 
00114 // ######################################################################
00115 FpuPrecision getFpuPrecision()
00116 {
00117 #ifdef INVT_CPU_IX86
00118   const unsigned short ctrl = get_x87_control_word();
00119   const unsigned short precbits = (ctrl & ((1<<9)|(1<<8))) >> 8;
00120   switch (precbits)
00121     {
00122     case 0: return FPU_PREC_SINGLE; // 00
00123     case 2: return FPU_PREC_DOUBLE; // 10
00124     case 3: return FPU_PREC_EXTENDED; // 11
00125     }
00126   LINFO("bogus x87 precision control bits '%d'", precbits);
00127   return FPU_PREC_EXTENDED;
00128 #else
00129   LDEBUG("warning: x87 control word not available; "
00130          "assuming extended precision");
00131   return FPU_PREC_EXTENDED;
00132 #endif
00133 }
00134 
00135 // ######################################################################
00136 void setFpuPrecision(FpuPrecision prec)
00137 {
00138 #ifdef INVT_CPU_IX86
00139   volatile unsigned short ctrl = get_x87_control_word();
00140   switch (prec)
00141     {
00142     case FPU_PREC_SINGLE:
00143       ctrl &= (~(1<<8));
00144       ctrl &= (~(1<<9));
00145       set_x87_control_word(ctrl);
00146       break;
00147     case FPU_PREC_DOUBLE:
00148       ctrl &= (~(1<<8));
00149       ctrl |=   (1<<9);
00150       set_x87_control_word(ctrl);
00151       break;
00152     case FPU_PREC_EXTENDED:
00153       ctrl |=   (1<<8);
00154       ctrl |=   (1<<9);
00155       set_x87_control_word(ctrl);
00156       break;
00157     }
00158 #else
00159   if (prec != FPU_PREC_EXTENDED)
00160     LERROR("warning: x87 control word not available; "
00161            "attempt to set precision to non-default value '%s' ignored",
00162            convertToString(prec).c_str());
00163 #endif
00164 }
00165 
00166 // ######################################################################
00167 std::string convertToString(const FpuPrecision& val)
00168 {
00169   switch (val)
00170     {
00171     case FPU_PREC_SINGLE: return "single";
00172     case FPU_PREC_DOUBLE: return "double";
00173     case FPU_PREC_EXTENDED: return "extended";
00174     }
00175   LFATAL("unknown FpuPrecision enumerant '%d'", int(val));
00176   /* can't happen */ return std::string();
00177 }
00178 
00179 // ######################################################################
00180 void convertFromString(const std::string& str, FpuPrecision& val)
00181 {
00182   if      (str.compare("single") == 0)   { val = FPU_PREC_SINGLE; }
00183   else if (str.compare("double") == 0)   { val = FPU_PREC_DOUBLE; }
00184   else if (str.compare("extended") == 0) { val = FPU_PREC_EXTENDED; }
00185   else
00186     conversion_error::raise<FpuPrecision>(str);
00187 }
00188 
00189 // ######################################################################
00190 FpuRoundingMode getFpuRoundingMode()
00191 {
00192 #ifdef INVT_CPU_IX86
00193   const unsigned short ctrl = get_x87_control_word();
00194   const unsigned short roundbits = (ctrl & ((1<<11)|(1<<10))) >> 10;
00195   switch (roundbits)
00196     {
00197     case 0: return FPU_ROUND_NEAR; // 00
00198     case 1: return FPU_ROUND_DOWN; // 01
00199     case 2: return FPU_ROUND_UP;   // 10
00200     case 3: return FPU_ROUND_ZERO; // 11
00201     }
00202   LINFO("bogus x87 precision control bits '%d'", roundbits);
00203   return FPU_ROUND_NEAR;
00204 #else
00205   LDEBUG("warning: x87 control word not available; "
00206          "assuming round-nearest");
00207   return FPU_ROUND_NEAR;
00208 #endif
00209 }
00210 
00211 // ######################################################################
00212 void setFpuRoundingMode(FpuRoundingMode roundmode)
00213 {
00214 #ifdef INVT_CPU_IX86
00215   volatile unsigned short ctrl = get_x87_control_word();
00216   switch (roundmode)
00217     {
00218     case FPU_ROUND_NEAR: // 00
00219       ctrl &= (~(1<<11));
00220       ctrl &= (~(1<<10));
00221       set_x87_control_word(ctrl);
00222       break;
00223     case FPU_ROUND_DOWN: // 01
00224       ctrl &= (~(1<<11));
00225       ctrl |=   (1<<10);
00226       set_x87_control_word(ctrl);
00227       break;
00228     case FPU_ROUND_UP:   // 10
00229       ctrl |=   (1<<11);
00230       ctrl &= (~(1<<10));
00231       set_x87_control_word(ctrl);
00232       break;
00233     case FPU_ROUND_ZERO: // 11
00234       ctrl |=   (1<<11);
00235       ctrl |=   (1<<10);
00236       set_x87_control_word(ctrl);
00237       break;
00238     }
00239 #else
00240   if (roundmode != FPU_ROUND_NEAR)
00241     LERROR("warning: x87 control word not available; "
00242            "attempt to set rounding mode to non-default value '%s' ignored",
00243            convertToString(roundmode).c_str());
00244 #endif
00245 }
00246 
00247 // ######################################################################
00248 std::string convertToString(const FpuRoundingMode& val)
00249 {
00250   switch (val)
00251     {
00252     case FPU_ROUND_NEAR: return "nearest";
00253     case FPU_ROUND_DOWN: return "down";
00254     case FPU_ROUND_UP:   return "up";
00255     case FPU_ROUND_ZERO: return "zero";
00256     }
00257   LFATAL("unknown FpuRoundingMode enumerant '%d'", int(val));
00258   /* can't happen */ return std::string();
00259 }
00260 
00261 // ######################################################################
00262 void convertFromString(const std::string& str, FpuRoundingMode& val)
00263 {
00264   if      (str.compare("nearest") == 0) { val = FPU_ROUND_NEAR; }
00265   else if (str.compare("down") == 0)    { val = FPU_ROUND_DOWN; }
00266   else if (str.compare("up") == 0)      { val = FPU_ROUND_UP; }
00267   else if (str.compare("zero") == 0)    { val = FPU_ROUND_ZERO; }
00268   else
00269     conversion_error::raise<FpuRoundingMode>(str);
00270 }
00271 
00272 // ######################################################################
00273 /* So things look consistent in everyone's emacs... */
00274 /* Local Variables: */
00275 /* indent-tabs-mode: nil */
00276 /* End: */
00277 
00278 #endif // UTIL_FPU_C_DEFINED
Generated on Sun May 8 08:42:26 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3