winCPUInfo.cc 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "platformWin32/platformWin32.h"
  24. #include "console/console.h"
  25. #include "string/stringTable.h"
  26. #include <math.h>
  27. extern void PlatformBlitInit();
  28. extern void SetProcessorInfo(TorqueSystemInfo::Processor& pInfo,
  29. char* vendor, U32 processor, U32 properties); // platform/platformCPU.cc
  30. #if defined(TORQUE_SUPPORTS_NASM)
  31. // asm cpu detection routine from platform code
  32. extern "C"
  33. {
  34. void detectX86CPUInfo(char *vendor, U32 *processor, U32 *properties);
  35. }
  36. #endif
  37. void Processor::init()
  38. {
  39. Con::printSeparator();
  40. Con::printf("Processor Initialization:");
  41. // Reference:
  42. // www.cyrix.com
  43. // www.amd.com
  44. // www.intel.com
  45. // http://developer.intel.com/design/PentiumII/manuals/24512701.pdf
  46. PlatformSystemInfo.processor.type = CPU_X86Compatible;
  47. PlatformSystemInfo.processor.name = StringTable->insert("Unknown x86 Compatible");
  48. PlatformSystemInfo.processor.mhz = 0;
  49. PlatformSystemInfo.processor.properties = CPU_PROP_C;
  50. char vendor[13] = {0,};
  51. U32 properties = 0;
  52. U32 processor = 0;
  53. #if defined(TORQUE_SUPPORTS_NASM)
  54. detectX86CPUInfo(vendor, &processor, &properties);
  55. #elif defined(TORQUE_SUPPORTS_VC_INLINE_X86_ASM)
  56. __asm
  57. {
  58. //--------------------------------------
  59. // is CPUID supported
  60. push ebx
  61. push edx
  62. push ecx
  63. pushfd
  64. pushfd // save EFLAGS to stack
  65. pop eax // move EFLAGS into EAX
  66. mov ebx, eax
  67. xor eax, 0x200000 // flip bit 21
  68. push eax
  69. popfd // restore EFLAGS
  70. pushfd
  71. pop eax
  72. cmp eax, ebx
  73. jz EXIT // doesn't support CPUID instruction
  74. //--------------------------------------
  75. // Get Vendor Informaion using CPUID eax==0
  76. xor eax, eax
  77. cpuid
  78. mov DWORD PTR vendor, ebx
  79. mov DWORD PTR vendor+4, edx
  80. mov DWORD PTR vendor+8, ecx
  81. // get Generic Extended CPUID info
  82. mov eax, 1
  83. cpuid // eax=1, so cpuid queries feature information
  84. and eax, 0x0ff0
  85. mov processor, eax // just store the model bits
  86. mov properties, edx
  87. // Want to check for 3DNow(tm). Need to see if extended cpuid functions present.
  88. mov eax, 0x80000000
  89. cpuid
  90. cmp eax, 0x80000000
  91. jbe MAYBE_3DLATER
  92. mov eax, 0x80000001
  93. cpuid
  94. and edx, 0x80000000 // 3DNow if bit 31 set -> put bit in our properties
  95. or properties, edx
  96. MAYBE_3DLATER:
  97. EXIT:
  98. popfd
  99. pop ecx
  100. pop edx
  101. pop ebx
  102. }
  103. #endif
  104. SetProcessorInfo(PlatformSystemInfo.processor, vendor, processor, properties);
  105. // now calculate speed of processor...
  106. U16 nearmhz = 0; // nearest rounded mhz
  107. U16 mhz = 0; // calculated value.
  108. #if defined(TORQUE_SUPPORTS_VC_INLINE_X86_ASM) || defined(TORQUE_COMPILER_MINGW)
  109. //--------------------------------------
  110. // if RDTSC support calculate the aproximate Mhz of the CPU
  111. if (PlatformSystemInfo.processor.properties & CPU_PROP_RDTSC &&
  112. PlatformSystemInfo.processor.properties & CPU_PROP_FPU)
  113. {
  114. const U32 msToWait = 1000; // bigger this is, more accurate we are.
  115. U32 tsLo1 = 0, tsHi1 = 0; // time stamp storage.
  116. U32 tsLo2 = 0, tsHi2 = 0; // time stamp storage.
  117. U16 Nearest66Mhz = 0, Delta66Mhz = 0;
  118. U16 Nearest50Mhz = 0, Delta50Mhz = 0;
  119. F64 tsFirst, tsSecond, tsDelta;
  120. U32 ms;
  121. // starting time marker.
  122. ms = GetTickCount(); // !!!!TBD - this function may have too high an error... dunno.
  123. #if defined(TORQUE_COMPILER_MINGW)
  124. asm ("rdtsc" : "=a" (tsLo1), "=d" (tsHi1));
  125. #elif defined(TORQUE_SUPPORTS_VC_INLINE_X86_ASM) // VC|CW
  126. __asm
  127. {
  128. push eax
  129. push edx
  130. rdtsc
  131. mov tsLo1, eax
  132. mov tsHi1, edx
  133. pop edx
  134. pop eax
  135. }
  136. #endif
  137. // the faster this check and exit is, the more accurate the time-stamp-delta will be.
  138. while(GetTickCount() < ms + msToWait) {};
  139. #if defined(TORQUE_COMPILER_MINGW)
  140. asm ("rdtsc" : "=a" (tsLo2), "=d" (tsHi2));
  141. #elif defined(TORQUE_SUPPORTS_VC_INLINE_X86_ASM) // VC|CW
  142. __asm
  143. {
  144. push eax
  145. push edx
  146. rdtsc
  147. mov tsLo2, eax
  148. mov tsHi2, edx
  149. pop edx
  150. pop eax
  151. }
  152. #endif
  153. // do calculations in doubles for accuracy, since we're working with 64-bit math here...
  154. // grabbed this from the MINGW sample.
  155. tsFirst = ((F64)tsHi1 * (F64)0x10000 * (F64)0x10000) + (F64)tsLo1;
  156. tsSecond = ((F64)tsHi2 * (F64)0x10000 * (F64)0x10000) + (F64)tsLo2;
  157. // get the timestamp delta. potentially large number here, as it's in Hz.
  158. tsDelta = tsSecond - tsFirst;
  159. // adjust for slightly-off-delay -- better to assume +1ms than try to really calc.
  160. tsDelta *= (F64)(msToWait + 1);
  161. tsDelta /= (F64)msToWait;
  162. // factor back into 1s of time.
  163. tsDelta *= ((F64)1000/(F64)msToWait);
  164. // then convert into Mhz
  165. tsDelta /= (F64)1000000;
  166. tsDelta += 0.5f; // trying to get closer to the right values, effectively rounding up.
  167. mhz = (U32)tsDelta;
  168. // Find nearest full/half multiple of 66/133 MHz
  169. Nearest66Mhz = ((((mhz * 3) + 100) / 200) * 200) / 3;
  170. // 660 = 1980 = 2080 = 100 = 2000 = 666
  171. // 440 = 1320 = 1420 = 70 = 1400 = 466
  172. // find delta to nearest 66 multiple.
  173. Delta66Mhz = abs(Nearest66Mhz - mhz);
  174. // Find nearest full/half multiple of 100 MHz
  175. Nearest50Mhz = (((mhz + 25) / 50) * 50);
  176. // 440 = 465 = 9 = 450
  177. // find delta to nearest 50 multiple.
  178. Delta50Mhz = abs(Nearest50Mhz - mhz);
  179. if (Delta50Mhz < Delta66Mhz) // closer to a 50 boundary
  180. nearmhz = Nearest50Mhz;
  181. else
  182. {
  183. nearmhz = Nearest66Mhz;
  184. if (nearmhz==666) // hack around -- !!!!TBD - other cases?!?!
  185. nearmhz = 667;
  186. }
  187. // !!!TBD
  188. // would be nice if we stored both the calculated and the adjusted/guessed values.
  189. PlatformSystemInfo.processor.mhz = nearmhz; // hold onto adjusted value only.
  190. }
  191. #endif
  192. if (mhz==0)
  193. {
  194. Con::printf(" %s, (Unknown) Mhz", PlatformSystemInfo.processor.name);
  195. // stick SOMETHING in so it isn't ZERO.
  196. PlatformSystemInfo.processor.mhz = 200; // seems a decent value.
  197. }
  198. else
  199. {
  200. if (nearmhz >= 1000)
  201. Con::printf(" %s, ~%.2f Ghz", PlatformSystemInfo.processor.name, ((float)nearmhz)/1000.0f);
  202. else
  203. Con::printf(" %s, ~%d Mhz", PlatformSystemInfo.processor.name, nearmhz);
  204. if (nearmhz != mhz)
  205. {
  206. if (mhz >= 1000)
  207. Con::printf(" (timed at roughly %.2f Ghz)", ((float)mhz)/1000.0f);
  208. else
  209. Con::printf(" (timed at roughly %d Mhz)", mhz);
  210. }
  211. }
  212. if (PlatformSystemInfo.processor.properties & CPU_PROP_FPU)
  213. Con::printf(" FPU detected");
  214. if (PlatformSystemInfo.processor.properties & CPU_PROP_MMX)
  215. Con::printf(" MMX detected");
  216. if (PlatformSystemInfo.processor.properties & CPU_PROP_3DNOW)
  217. Con::printf(" 3DNow detected");
  218. if (PlatformSystemInfo.processor.properties & CPU_PROP_SSE)
  219. Con::printf(" SSE detected");
  220. Con::printf(" ");
  221. PlatformBlitInit();
  222. }