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