diff --git a/source/glest_game/game/game.cpp b/source/glest_game/game/game.cpp index 1a7aead0..86a89aec 100644 --- a/source/glest_game/game/game.cpp +++ b/source/glest_game/game/game.cpp @@ -24,6 +24,7 @@ #include "network_manager.h" #include "checksum.h" #include "auto_test.h" +#include "FPUCheck.h" #include "leak_dumper.h" using namespace Shared::Graphics; @@ -98,6 +99,7 @@ void Game::load(){ } Config &config = Config::getInstance(); + good_fpu_control_registers(NULL,__FILE__,__FUNCTION__,__LINE__); string scenarioDir = ""; if(gameSettings.getScenarioDir() != "") { @@ -212,6 +214,8 @@ void Game::load(){ Lang::getInstance().loadScenarioStrings(gameSettings.getScenarioDir(), scenarioName); world.loadScenario(gameSettings.getScenarioDir(), &checksum); } + + good_fpu_control_registers(NULL,__FILE__,__FUNCTION__,__LINE__); } void Game::init() @@ -243,6 +247,8 @@ void Game::init() gameCamera.setPos(Vec2f(v.x, v.y)); scriptManager.init(&world, &gameCamera); + good_fpu_control_registers(NULL,__FILE__,__FUNCTION__,__LINE__); + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] creating AI's\n",__FILE__,__FUNCTION__); //create IAs @@ -280,6 +286,8 @@ void Game::init() logger.add("Initializing renderer", true); renderer.initGame(this); + good_fpu_control_registers(NULL,__FILE__,__FUNCTION__,__LINE__); + //sounds SoundRenderer &soundRenderer= SoundRenderer::getInstance(); @@ -356,6 +364,8 @@ void Game::update(){ weatherParticleSystem->setPos(gameCamera.getPos()); } renderer.updateParticleManager(rsGame); + + good_fpu_control_registers(NULL,__FILE__,__FUNCTION__,__LINE__); } //call the chat manager diff --git a/source/shared_lib/include/streflop/FPUCheck.h b/source/shared_lib/include/streflop/FPUCheck.h new file mode 100644 index 00000000..257a27a1 --- /dev/null +++ b/source/shared_lib/include/streflop/FPUCheck.h @@ -0,0 +1,119 @@ +/** + * @file FPUCheck.h + * @brief good_fpu_control_registers function + * @author Tobi Vollebregt + * + * Assertions on floating point unit control registers. + * For now it only defines the good_fpu_control_registers() function. + * + * Copyright (C) 2006. Licensed under the terms of the + * GNU GPL, v2 or later + */ + +#ifndef FPUCHECK_H +#define FPUCHECK_H + +//#include "LogOutput.h" +#include "util.h" +#include "streflop_cond.h" + +/** + @brief checks FPU control registers. + @return true if everything is fine, false otherwise + + Can be used in an assert() to check the FPU control registers MXCSR and FPUCW, + e.g. `assert(good_fpu_control_registers());' + + For reference, the layout of the MXCSR register: + FZ:RC:RC:PM:UM:OM:ZM:DM:IM:Rsvd:PE:UE:OE:ZE:DE:IE + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +Spring1: 0 0 0 1 1 1 0 1 0 0 0 0 0 0 0 0 = 0x1D00 = 7424 +Spring2: 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 = 0x1F80 = 8064 +Default: 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 = 0x1F80 = 8064 +MaskRsvd:1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 = 0xFF80 + + And the layout of the 387 FPU control word register: + Rsvd:Rsvd:Rsvd:X:RC:RC:PC:PC:Rsvd:Rsvd:PM:UM:OM:ZM:DM:IM + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +Spring1: 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 0 = 0x003A = 58 +Spring2: 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 = 0x003F = 63 +Default: 0 0 0 0 0 0 1 1 0 0 1 1 1 1 1 1 = 0x033F = 831 +MaskRsvd: 0 0 0 1 1 1 1 1 0 0 1 1 1 1 1 1 = 0x1F3F + + Where: + Rsvd - Reserved + FZ - Flush to Zero + RC - Rounding Control + PM - Precision Mask + UM - Underflow Mask + OM - Overflow Mask + ZM - Zerodivide Mask + DM - Denormal Mask + IM - Invalid Mask + PE - Precision Exception + UE - Underflow Exception + OE - Overflow Exception + ZE - Zerodivide Exception + DE - Denormal Exception + IE - Invalid Exception + X - Infinity control (unused on 387 and higher) + PC - Precision Control + + Spring1 - Control word used by spring in code in CGame::SimFrame(). + Spring2 - Control word used by spring in code everywhere else. + Default - Default control word according to Intel. + MaskRsvd - Masks out the reserved bits. + + Source: Intel Architecture Software Development Manual, Volume 1, Basic Architecture +*/ +static inline void good_fpu_control_registers(const char* text, const char *file=NULL, const char *classname=NULL, const int line=-1) +{ + const char *outText = text; + char szBuf[256]=""; + if(outText == NULL) { + sprintf(szBuf,"In [%s::%s Line: %d]",file=NULL, classname, line); + outText = &szBuf[0]; + } + // We are paranoid. + // We don't trust the enumeration constants from streflop / (g)libc. +#if defined(STREFLOP_SSE) + fenv_t fenv; + fegetenv(&fenv); + + #if defined(__SUPPORT_SNAN__) && !defined(USE_GML) // -fsignaling-nans + bool ret = ((fenv.sse_mode & 0xFF80) == (0x1937 & 0xFF80) || (fenv.sse_mode & 0xFF80) == (0x1925 & 0xFF80)) && + ((fenv.x87_mode & 0x1F3F) == (0x0072 & 0x1F3F) || (fenv.x87_mode & 0x1F3F) == 0x003F); + #else + bool ret = ((fenv.sse_mode & 0xFF80) == 0x1D00 || (fenv.sse_mode & 0xFF80) == 0x1F80) && + ((fenv.x87_mode & 0x1F3F) == 0x003A || (fenv.x87_mode & 0x1F3F) == 0x003F); + #endif + + if (!ret) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"Sync warning: MXCSR 0x%04X instead of 0x1D00 or 0x1F80 (\"%s\")", fenv.sse_mode, outText); + SystemFlags::OutputDebug(SystemFlags::debugSystem,"Sync warning: FPUCW 0x%04X instead of 0x003A or 0x003F (\"%s\")", fenv.x87_mode, outText); + // Set single precision floating point math. + streflop_init(); + #if defined(__SUPPORT_SNAN__) && !defined(USE_GML) + feraiseexcept(streflop::FPU_Exceptions(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW)); + #endif + } +#elif defined(STREFLOP_X87) + fenv_t fenv; + fegetenv(&fenv); + #if defined(__SUPPORT_SNAN__) && !defined(USE_GML) + bool ret = (fenv & 0x1F3F) == 0x0072 || (fenv & 0x1F3F) == 0x003F; + #else + bool ret = (fenv & 0x1F3F) == 0x003A || (fenv & 0x1F3F) == 0x003F; + #endif + if (!ret) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"Sync warning: FPUCW 0x%04X instead of 0x003A or 0x003F (\"%s\")", fenv, outText); + // Set single precision floating point math. + streflop_init(); + #if defined(__SUPPORT_SNAN__) && !defined(USE_GML) + feraiseexcept(streflop::FPU_Exceptions(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW)); + #endif + } +#endif +} + +#endif // !FPUCHECK_H