cpudetect.cpp 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "cpudetect.h"
  19. #include "wwstring.h"
  20. #include "wwdebug.h"
  21. #include "thread.h"
  22. #include "mpu.h"
  23. #pragma warning (disable : 4201) // Nonstandard extension - nameless struct
  24. #include <windows.h>
  25. #include "systimer.h"
  26. #ifdef _UNIX
  27. # include <time.h> // for time(), localtime() and timezone variable.
  28. #endif
  29. struct OSInfoStruct {
  30. const char* Code;
  31. const char* SubCode;
  32. const char* VersionString;
  33. unsigned char VersionMajor;
  34. unsigned char VersionMinor;
  35. unsigned short VersionSub;
  36. unsigned char BuildMajor;
  37. unsigned char BuildMinor;
  38. unsigned short BuildSub;
  39. };
  40. static void Get_OS_Info(
  41. OSInfoStruct& os_info,
  42. unsigned OSVersionPlatformId,
  43. unsigned OSVersionNumberMajor,
  44. unsigned OSVersionNumberMinor,
  45. unsigned OSVersionBuildNumber);
  46. StringClass CPUDetectClass::ProcessorLog;
  47. StringClass CPUDetectClass::CompactLog;
  48. int CPUDetectClass::ProcessorType;
  49. int CPUDetectClass::ProcessorFamily;
  50. int CPUDetectClass::ProcessorModel;
  51. int CPUDetectClass::ProcessorRevision;
  52. int CPUDetectClass::ProcessorSpeed;
  53. __int64 CPUDetectClass::ProcessorTicksPerSecond; // Ticks per second
  54. double CPUDetectClass::InvProcessorTicksPerSecond; // 1.0 / Ticks per second
  55. unsigned CPUDetectClass::FeatureBits;
  56. unsigned CPUDetectClass::ExtendedFeatureBits;
  57. unsigned CPUDetectClass::L2CacheSize;
  58. unsigned CPUDetectClass::L2CacheLineSize;
  59. unsigned CPUDetectClass::L2CacheSetAssociative;
  60. unsigned CPUDetectClass::L1DataCacheSize;
  61. unsigned CPUDetectClass::L1DataCacheLineSize;
  62. unsigned CPUDetectClass::L1DataCacheSetAssociative;
  63. unsigned CPUDetectClass::L1InstructionCacheSize;
  64. unsigned CPUDetectClass::L1InstructionCacheLineSize;
  65. unsigned CPUDetectClass::L1InstructionCacheSetAssociative;
  66. unsigned CPUDetectClass::L1InstructionTraceCacheSize;
  67. unsigned CPUDetectClass::L1InstructionTraceCacheSetAssociative;
  68. unsigned CPUDetectClass::TotalPhysicalMemory;
  69. unsigned CPUDetectClass::AvailablePhysicalMemory;
  70. unsigned CPUDetectClass::TotalPageMemory;
  71. unsigned CPUDetectClass::AvailablePageMemory;
  72. unsigned CPUDetectClass::TotalVirtualMemory;
  73. unsigned CPUDetectClass::AvailableVirtualMemory;
  74. unsigned CPUDetectClass::OSVersionNumberMajor;
  75. unsigned CPUDetectClass::OSVersionNumberMinor;
  76. unsigned CPUDetectClass::OSVersionBuildNumber;
  77. unsigned CPUDetectClass::OSVersionPlatformId;
  78. StringClass CPUDetectClass::OSVersionExtraInfo;
  79. bool CPUDetectClass::HasCPUIDInstruction=false;
  80. bool CPUDetectClass::HasRDTSCInstruction=false;
  81. bool CPUDetectClass::HasSSESupport=false;
  82. bool CPUDetectClass::HasSSE2Support=false;
  83. bool CPUDetectClass::HasCMOVSupport=false;
  84. bool CPUDetectClass::HasMMXSupport=false;
  85. bool CPUDetectClass::Has3DNowSupport=false;
  86. bool CPUDetectClass::HasExtended3DNowSupport=false;
  87. CPUDetectClass::ProcessorManufacturerType CPUDetectClass::ProcessorManufacturer = CPUDetectClass::MANUFACTURER_UNKNOWN;
  88. CPUDetectClass::IntelProcessorType CPUDetectClass::IntelProcessor;
  89. CPUDetectClass::AMDProcessorType CPUDetectClass::AMDProcessor;
  90. CPUDetectClass::VIAProcessorType CPUDetectClass::VIAProcessor;
  91. CPUDetectClass::RiseProcessorType CPUDetectClass::RiseProcessor;
  92. char CPUDetectClass::VendorID[20];
  93. char CPUDetectClass::ProcessorString[48];
  94. const char* CPUDetectClass::Get_Processor_Manufacturer_Name()
  95. {
  96. static const char* ManufacturerNames[] = {
  97. "<Unknown>",
  98. "Intel",
  99. "UMC",
  100. "AMD",
  101. "Cyrix",
  102. "NextGen",
  103. "VIA",
  104. "Rise",
  105. "Transmeta"
  106. };
  107. return ManufacturerNames[ProcessorManufacturer];
  108. }
  109. #define ASM_RDTSC _asm _emit 0x0f _asm _emit 0x31
  110. static unsigned Calculate_Processor_Speed(__int64& ticks_per_second)
  111. {
  112. struct {
  113. unsigned timer0_h;
  114. unsigned timer0_l;
  115. unsigned timer1_h;
  116. unsigned timer1_l;
  117. } Time;
  118. #ifdef WIN32
  119. __asm {
  120. ASM_RDTSC;
  121. mov Time.timer0_h, eax
  122. mov Time.timer0_l, edx
  123. }
  124. #elif defined(_UNIX)
  125. __asm__("rdtsc");
  126. __asm__("mov %eax, __Time.timer1_h");
  127. __asm__("mov %edx, __Time.timer1_l");
  128. #endif
  129. unsigned start=TIMEGETTIME();
  130. unsigned elapsed;
  131. while ((elapsed=TIMEGETTIME()-start)<200) {
  132. #ifdef WIN32
  133. __asm {
  134. ASM_RDTSC;
  135. mov Time.timer1_h, eax
  136. mov Time.timer1_l, edx
  137. }
  138. #elif defined(_UNIX)
  139. __asm__ ("rdtsc");
  140. __asm__("mov %eax, __Time.timer1_h");
  141. __asm__("mov %edx, __Time.timer1_l");
  142. #endif
  143. }
  144. __int64 t=*(__int64*)&Time.timer1_h-*(__int64*)&Time.timer0_h;
  145. ticks_per_second=(__int64)((1000.0/(double)elapsed)*(double)t); // Ticks per second
  146. return unsigned((double)t/(double)(elapsed*1000));
  147. }
  148. void CPUDetectClass::Init_Processor_Speed()
  149. {
  150. if (!Has_RDTSC_Instruction()) {
  151. ProcessorSpeed=0;
  152. return;
  153. }
  154. // Loop until two subsequent samples are within 5% of each other (max 5 iterations).
  155. unsigned speed1=Calculate_Processor_Speed(ProcessorTicksPerSecond);
  156. unsigned total_speed=speed1;
  157. for (int i=0;i<5;++i) {
  158. unsigned speed2=Calculate_Processor_Speed(ProcessorTicksPerSecond);
  159. float rel=float(speed1)/float(speed2);
  160. if (rel>=0.95f && rel<=1.05f) {
  161. ProcessorSpeed=(speed1+speed2)/2;
  162. InvProcessorTicksPerSecond=1.0/double(ProcessorTicksPerSecond);
  163. return;
  164. }
  165. speed1=speed2;
  166. total_speed+=speed2;
  167. }
  168. // If no two subsequent samples where close enough, use intermediate
  169. ProcessorSpeed=total_speed/6;
  170. InvProcessorTicksPerSecond=1.0/double(ProcessorTicksPerSecond);
  171. }
  172. void CPUDetectClass::Init_Processor_Manufacturer()
  173. {
  174. VendorID[0] = 0;
  175. unsigned max_cpuid;
  176. CPUID(
  177. max_cpuid,
  178. (unsigned&)VendorID[0],
  179. (unsigned&)VendorID[8],
  180. (unsigned&)VendorID[4],
  181. 0);
  182. ProcessorManufacturer = MANUFACTURER_UNKNOWN;
  183. if (stricmp(VendorID, "GenuineIntel") == 0) ProcessorManufacturer = MANUFACTURER_INTEL;
  184. else if (stricmp(VendorID, "AuthenticAMD") == 0) ProcessorManufacturer = MANUFACTURER_AMD;
  185. else if (stricmp(VendorID, "AMD ISBETTER") == 0) ProcessorManufacturer = MANUFACTURER_AMD;
  186. else if (stricmp(VendorID, "UMC UMC UMC") == 0) ProcessorManufacturer = MANUFACTURER_UMC;
  187. else if (stricmp(VendorID, "CyrixInstead") == 0) ProcessorManufacturer = MANUFACTURER_CYRIX;
  188. else if (stricmp(VendorID, "NexGenDriven") == 0) ProcessorManufacturer = MANUFACTURER_NEXTGEN;
  189. else if (stricmp(VendorID, "CentaurHauls") == 0) ProcessorManufacturer = MANUFACTURER_VIA;
  190. else if (stricmp(VendorID, "RiseRiseRise") == 0) ProcessorManufacturer = MANUFACTURER_RISE;
  191. else if (stricmp(VendorID, "GenuineTMx86") == 0) ProcessorManufacturer = MANUFACTURER_TRANSMETA;
  192. }
  193. void CPUDetectClass::Process_Cache_Info(unsigned value)
  194. {
  195. switch (value) {
  196. case 0x00: // Null
  197. break;
  198. case 0x01: // Instruction TLB, 4K pages, 4-way set associative, 32 entries
  199. break;
  200. case 0x02: // Instruction TLB, 4M pages, fully associative, 2 entries
  201. break;
  202. case 0x03: // Data TLB, 4K pages, 4-way set associative, 64 entries
  203. break;
  204. case 0x04: // Data TLB, 4M pages, 4-way set associative, 8 entries
  205. break;
  206. case 0x06: // Instruction cache, 8K, 4-way set associative, 32 byte line size
  207. L1InstructionCacheSize=8*1024;
  208. L1InstructionCacheLineSize=32;
  209. L1InstructionCacheSetAssociative=4;
  210. break;
  211. case 0x08: // Instruction cache 16K, 4-way set associative, 32 byte line size
  212. L1InstructionCacheSize=16*1024;
  213. L1InstructionCacheLineSize=32;
  214. L1InstructionCacheSetAssociative=4;
  215. break;
  216. case 0x0A: // Data cache, 8K, 2-way set associative, 32 byte line size
  217. L1DataCacheSize=8*1024;
  218. L1DataCacheLineSize=32;
  219. L1DataCacheSetAssociative=2;
  220. break;
  221. case 0x0C: // Data cache, 16K, 4-way set associative, 32 byte line size
  222. L1DataCacheSize=16*1024;
  223. L1DataCacheLineSize=32;
  224. L1DataCacheSetAssociative=4;
  225. break;
  226. case 0x40: // No L2 cache (P6 family), or No L3 cache (Pentium 4 processor)
  227. // Nice of Intel, Pentium4 has an exception and this field is defined as "no L3 cache"
  228. if (ProcessorManufacturer==MANUFACTURER_INTEL && ProcessorFamily==0xf) {
  229. }
  230. else {
  231. L2CacheSize=0;
  232. L2CacheLineSize=0;
  233. L2CacheSetAssociative=0;
  234. }
  235. break;
  236. case 0x41: // Unified cache, 32 byte cache line,4-way set associative, 128K
  237. L2CacheSize=128*1024;
  238. L2CacheLineSize=32;
  239. L2CacheSetAssociative=4;
  240. break;
  241. case 0x42: // Unified cache, 32 byte cache line, 4-way set associative, 256K
  242. L2CacheSize=256*1024;
  243. L2CacheLineSize=32;
  244. L2CacheSetAssociative=4;
  245. break;
  246. case 0x43: // Unified cache, 32 byte cache line, 4-way set associative, 512K
  247. L2CacheSize=512*1024;
  248. L2CacheLineSize=32;
  249. L2CacheSetAssociative=4;
  250. break;
  251. case 0x44: // Unified cache, 32 byte cache line, 4-way set associative, 1M
  252. L2CacheSize=1024*1024;
  253. L2CacheLineSize=32;
  254. L2CacheSetAssociative=4;
  255. break;
  256. case 0x45: // Unified cache, 32 byte cache line, 4-way set associative, 2M
  257. L2CacheSize=2048*1024;
  258. L2CacheLineSize=32;
  259. L2CacheSetAssociative=4;
  260. break;
  261. case 0x50: // Instruction TLB, 4K, 2M or 4M pages, fully associative, 64 entries
  262. break;
  263. case 0x51: // Instruction TLB, 4K, 2M or 4M pages, fully associative, 128 entries
  264. break;
  265. case 0x52: // Instruction TLB, 4K, 2M or 4M pages, fully associative, 256 entries
  266. break;
  267. case 0x5B: // Data TLB, 4K or 4M pages, fully associative, 64 entries
  268. break;
  269. case 0x5C: // Data TLB, 4K or 4M pages, fully associative, 128 entries
  270. break;
  271. case 0x5D: // Data TLB, 4K or 4M pages, fully associative, 256 entries
  272. break;
  273. case 0x66: // Data cache, sectored, 64 byte cache line, 4 way set associative, 8K
  274. L1DataCacheSize=8*1024;
  275. L1DataCacheLineSize=64;
  276. L1DataCacheSetAssociative=4;
  277. break;
  278. case 0x67: // Data cache, sectored, 64 byte cache line, 4 way set associative, 16K
  279. L1DataCacheSize=16*1024;
  280. L1DataCacheLineSize=64;
  281. L1DataCacheSetAssociative=4;
  282. break;
  283. case 0x68: // Data cache, sectored, 64 byte cache line, 4 way set associative, 32K
  284. L1DataCacheSize=32*1024;
  285. L1DataCacheLineSize=64;
  286. L1DataCacheSetAssociative=4;
  287. break;
  288. case 0x70: // Instruction Trace cache, 8 way set associative, 12K uOps
  289. L1InstructionTraceCacheSize=12*1024;
  290. L1InstructionTraceCacheSetAssociative=8;
  291. break;
  292. case 0x71: // Instruction Trace cache, 8 way set associative, 16K uOps
  293. L1InstructionTraceCacheSize=16*1024;
  294. L1InstructionTraceCacheSetAssociative=8;
  295. break;
  296. case 0x72: // Instruction Trace cache, 8 way set associative, 32K uOps
  297. L1InstructionTraceCacheSize=32*1024;
  298. L1InstructionTraceCacheSetAssociative=8;
  299. break;
  300. case 0x79: // Unified cache, sectored, 64 byte cache line, 8 way set associative, 128K
  301. L2CacheSize=128*1024;
  302. L2CacheLineSize=64;
  303. L2CacheSetAssociative=8;
  304. break;
  305. case 0x7A: // Unified cache, sectored, 64 byte cache line, 8 way set associative, 256K
  306. L2CacheSize=256*1024;
  307. L2CacheLineSize=64;
  308. L2CacheSetAssociative=8;
  309. break;
  310. case 0x7B: // Unified cache, sectored, 64 byte cache line, 8 way set associative, 512K
  311. L2CacheSize=512*1024;
  312. L2CacheLineSize=64;
  313. L2CacheSetAssociative=8;
  314. break;
  315. case 0x7C: // Unified cache, sectored, 64 byte cache line, 8 way set associative, 1M
  316. L2CacheSize=1024*1024;
  317. L2CacheLineSize=64;
  318. L2CacheSetAssociative=8;
  319. break;
  320. case 0x82: // Unified cache, 32 byte cache line, 8 way set associative, 256K
  321. L2CacheSize=256*1024;
  322. L2CacheLineSize=32;
  323. L2CacheSetAssociative=8;
  324. break;
  325. case 0x83: // Unified cache, 32 byte cache line, 8 way set associative, 512K
  326. L2CacheSize=512*1024;
  327. L2CacheLineSize=32;
  328. L2CacheSetAssociative=8;
  329. break;
  330. case 0x84: // Unified cache, 32 byte cache line, 8 way set associative, 1M
  331. L2CacheSize=1024*1024;
  332. L2CacheLineSize=32;
  333. L2CacheSetAssociative=8;
  334. break;
  335. case 0x85: // Unified cache, 32 byte cache line, 8 way set associative, 2M
  336. L2CacheSize=2048*1024;
  337. L2CacheLineSize=32;
  338. L2CacheSetAssociative=8;
  339. break;
  340. }
  341. }
  342. void CPUDetectClass::Process_Extended_Cache_Info()
  343. {
  344. CPUIDStruct max_ext(0x80000000);
  345. if (max_ext.Eax>=0x80000006) {
  346. CPUIDStruct l1info(0x80000005);
  347. CPUIDStruct l2info(0x80000006);
  348. // L1 data cache
  349. L1DataCacheLineSize=l1info.Ecx&0xff;
  350. L1DataCacheSetAssociative=(l1info.Ecx>>16)&0xff;
  351. L1DataCacheSize=((l1info.Ecx>>24)&0xff)*1024;
  352. // L1 instruction cache
  353. L1InstructionCacheLineSize=l1info.Edx&0xff;
  354. L1InstructionCacheSetAssociative=(l1info.Edx>>16)&0xff;
  355. L1InstructionCacheSize=((l1info.Edx>>24)&0xff)*1024;
  356. // L2 cache
  357. L2CacheSize=((l2info.Ecx>>16)&0xffff)*1024;
  358. L2CacheLineSize=l2info.Ecx&0xff;
  359. switch ((l2info.Ecx>>12)&0xf) {
  360. case 0: L2CacheSetAssociative=0; break;
  361. case 1: L2CacheSetAssociative=1; break;
  362. case 2: L2CacheSetAssociative=2; break;
  363. case 4: L2CacheSetAssociative=4; break;
  364. case 6: L2CacheSetAssociative=8; break;
  365. case 8: L2CacheSetAssociative=16; break;
  366. case 15: L2CacheSetAssociative=0xff; break;
  367. }
  368. }
  369. }
  370. void CPUDetectClass::Init_Cache()
  371. {
  372. CPUIDStruct cache_id(2);
  373. // This code can only determine cache sizes for cpuid count 1 (see Intel manuals for more info on the subject)
  374. if ((cache_id.Eax&0xff)==1) {
  375. if (!(cache_id.Eax&0x80000000)) {
  376. Process_Cache_Info((cache_id.Eax>>24)&0xff);
  377. Process_Cache_Info((cache_id.Eax>>16)&0xff);
  378. Process_Cache_Info((cache_id.Eax>>8)&0xff);
  379. }
  380. if (!(cache_id.Ebx&0x80000000)) {
  381. Process_Cache_Info((cache_id.Ebx>>24)&0xff);
  382. Process_Cache_Info((cache_id.Ebx>>16)&0xff);
  383. Process_Cache_Info((cache_id.Ebx>>8)&0xff);
  384. Process_Cache_Info((cache_id.Ebx)&0xff);
  385. }
  386. if (!(cache_id.Ecx&0x80000000)) {
  387. Process_Cache_Info((cache_id.Ecx>>24)&0xff);
  388. Process_Cache_Info((cache_id.Ecx>>16)&0xff);
  389. Process_Cache_Info((cache_id.Ecx>>8)&0xff);
  390. Process_Cache_Info((cache_id.Ecx)&0xff);
  391. }
  392. if (!(cache_id.Edx&0x80000000)) {
  393. Process_Cache_Info((cache_id.Edx>>24)&0xff);
  394. Process_Cache_Info((cache_id.Edx>>16)&0xff);
  395. Process_Cache_Info((cache_id.Edx>>8)&0xff);
  396. Process_Cache_Info((cache_id.Edx)&0xff);
  397. }
  398. }
  399. else {
  400. // If standard (Intel) cache information not found, try extended info.
  401. Process_Extended_Cache_Info();
  402. }
  403. }
  404. void CPUDetectClass::Init_Intel_Processor_Type()
  405. {
  406. switch (ProcessorFamily) {
  407. case 3:
  408. IntelProcessor=INTEL_PROCESSOR_80386;
  409. break;
  410. case 4:
  411. switch (ProcessorModel) {
  412. default:
  413. case 0:
  414. case 1:
  415. IntelProcessor=INTEL_PROCESSOR_80486DX;
  416. break;
  417. case 2:
  418. IntelProcessor=INTEL_PROCESSOR_80486SX;
  419. break;
  420. case 3:
  421. IntelProcessor=INTEL_PROCESSOR_80486DX2;
  422. break;
  423. case 4:
  424. IntelProcessor=INTEL_PROCESSOR_80486SL;
  425. break;
  426. case 5:
  427. IntelProcessor=INTEL_PROCESSOR_80486SX2;
  428. break;
  429. case 7:
  430. IntelProcessor=INTEL_PROCESSOR_80486DX2_WB;
  431. break;
  432. case 8:
  433. IntelProcessor=INTEL_PROCESSOR_80486DX4;
  434. break;
  435. case 9:
  436. IntelProcessor=INTEL_PROCESSOR_80486DX4_WB;
  437. break;
  438. }
  439. break;
  440. case 5:
  441. switch (ProcessorModel) {
  442. default:
  443. case 0:
  444. IntelProcessor=INTEL_PROCESSOR_PENTIUM; // Early model
  445. break;
  446. case 1:
  447. IntelProcessor=INTEL_PROCESSOR_PENTIUM; // 60/66, 5V
  448. break;
  449. case 2:
  450. IntelProcessor=INTEL_PROCESSOR_PENTIUM; // 75+, 3.xV
  451. break;
  452. case 3:
  453. IntelProcessor=INTEL_PROCESSOR_PENTIUM_OVERDRIVE;
  454. break;
  455. case 4:
  456. IntelProcessor=INTEL_PROCESSOR_PENTIUM_MMX;
  457. break;
  458. case 5:
  459. IntelProcessor=INTEL_PROCESSOR_PENTIUM_OVERDRIVE;
  460. break;
  461. case 6:
  462. IntelProcessor=INTEL_PROCESSOR_PENTIUM_OVERDRIVE;
  463. break;
  464. case 7:
  465. IntelProcessor=INTEL_PROCESSOR_PENTIUM;
  466. break;
  467. case 8:
  468. IntelProcessor=INTEL_PROCESSOR_PENTIUM_MMX;
  469. break;
  470. }
  471. case 6:
  472. switch (ProcessorModel) {
  473. default:
  474. case 0:
  475. IntelProcessor=INTEL_PROCESSOR_PENTIUM_PRO_SAMPLE;
  476. break;
  477. case 1:
  478. IntelProcessor=INTEL_PROCESSOR_PENTIUM_PRO;
  479. break;
  480. case 3:
  481. if (ProcessorType==0) {
  482. IntelProcessor=INTEL_PROCESSOR_PENTIUM_II_MODEL_3;
  483. }
  484. else {
  485. IntelProcessor=INTEL_PROCESSOR_PENTIUM_II_OVERDRIVE;
  486. }
  487. break;
  488. case 4:
  489. IntelProcessor=INTEL_PROCESSOR_PENTIUM_II_MODEL_4;
  490. break;
  491. case 5:
  492. // This one is either PII, PIIXeon or Celeron with no L2 cache!
  493. {
  494. CPUIDStruct cache_id(2);
  495. // TODO: Check for cache to determine processor type!
  496. if (L2CacheSize==0) {
  497. IntelProcessor=INTEL_PROCESSOR_CELERON_MODEL_5;
  498. }
  499. else if (L2CacheSize<=512*1024) { // If Xeon has 512k L2 cache we will assume a PII - tough luck!
  500. IntelProcessor=INTEL_PROCESSOR_PENTIUM_II_MODEL_5;
  501. }
  502. else {
  503. IntelProcessor=INTEL_PROCESSOR_PENTIUM_II_XEON_MODEL_5;
  504. }
  505. }
  506. break;
  507. case 6:
  508. IntelProcessor=INTEL_PROCESSOR_CELERON_MODEL_6;
  509. break;
  510. case 7:
  511. if (L2CacheSize<=512*1024) { // If Xeon has 512k L2 cache we will assume a PIII - tough luck!
  512. IntelProcessor=INTEL_PROCESSOR_PENTIUM_III_MODEL_7;
  513. }
  514. else {
  515. IntelProcessor=INTEL_PROCESSOR_PENTIUM_III_XEON_MODEL_7;
  516. }
  517. break;
  518. case 8:
  519. // This could be PentiumIII Coppermine or Celeron with SSE, or a Xeon
  520. {
  521. CPUIDStruct brand(1);
  522. switch (brand.Ebx&0xff) {
  523. case 0x1: IntelProcessor=INTEL_PROCESSOR_CELERON_MODEL_8; break;
  524. case 0x2:
  525. case 0x4: IntelProcessor=INTEL_PROCESSOR_PENTIUM_III_MODEL_8; break;
  526. case 0x3:
  527. case 0xe: IntelProcessor=INTEL_PROCESSOR_PENTIUM_III_XEON_MODEL_8; break;
  528. }
  529. }
  530. break;
  531. case 0xa:
  532. IntelProcessor=INTEL_PROCESSOR_PENTIUM_III_XEON_MODEL_A;
  533. break;
  534. case 0xb:
  535. IntelProcessor=INTEL_PROCESSOR_PENTIUM_III_MODEL_B;
  536. break;
  537. }
  538. break;
  539. case 0xf:
  540. IntelProcessor=INTEL_PROCESSOR_PENTIUM4;
  541. break;
  542. }
  543. }
  544. void CPUDetectClass::Init_AMD_Processor_Type()
  545. {
  546. switch (ProcessorFamily) {
  547. case 4:
  548. switch (ProcessorModel) {
  549. case 3:
  550. AMDProcessor=AMD_PROCESSOR_486DX2;
  551. break;
  552. case 7:
  553. AMDProcessor=AMD_PROCESSOR_486DX4;
  554. break;
  555. case 8:
  556. AMDProcessor=AMD_PROCESSOR_486DX4;
  557. break;
  558. case 9:
  559. AMDProcessor=AMD_PROCESSOR_486DX4;
  560. break;
  561. case 0xe:
  562. AMDProcessor=AMD_PROCESSOR_5x86;
  563. break;
  564. case 0xf:
  565. AMDProcessor=AMD_PROCESSOR_5x86;
  566. break;
  567. default:
  568. AMDProcessor=AMD_PROCESSOR_486;
  569. }
  570. break;
  571. case 5:
  572. switch (ProcessorModel) {
  573. case 0:
  574. AMDProcessor=AMD_PROCESSOR_K5_MODEL0;
  575. break;
  576. case 1:
  577. AMDProcessor=AMD_PROCESSOR_K5_MODEL1;
  578. break;
  579. case 2:
  580. AMDProcessor=AMD_PROCESSOR_K5_MODEL2;
  581. break;
  582. case 3:
  583. AMDProcessor=AMD_PROCESSOR_K5_MODEL3;
  584. break;
  585. case 6:
  586. AMDProcessor=AMD_PROCESSOR_K6_MODEL6;
  587. break;
  588. case 7:
  589. AMDProcessor=AMD_PROCESSOR_K6_MODEL7;
  590. break;
  591. case 8:
  592. AMDProcessor=AMD_PROCESSOR_K6_2_3DNOW_MODEL8;
  593. break;
  594. case 9:
  595. AMDProcessor=AMD_PROCESSOR_K6_3_3DNOW_MODEL9;
  596. break;
  597. case 0xd:
  598. AMDProcessor=AMD_PROCESSOR_K6_3_PLUS;
  599. break;
  600. default:
  601. AMDProcessor=AMD_PROCESSOR_K6;
  602. }
  603. case 6:
  604. switch (ProcessorModel) {
  605. case 1:
  606. AMDProcessor=AMD_PROCESSOR_ATHLON_025;
  607. break;
  608. case 2:
  609. AMDProcessor=AMD_PROCESSOR_ATHLON_018;
  610. break;
  611. case 3:
  612. AMDProcessor=AMD_PROCESSOR_DURON;
  613. break;
  614. case 4:
  615. AMDProcessor=AMD_PROCESSOR_ATHLON_018_IL2;
  616. break;
  617. default:
  618. AMDProcessor=AMD_PROCESSOR_ATHLON;
  619. break;
  620. }
  621. }
  622. }
  623. void CPUDetectClass::Init_VIA_Processor_Type()
  624. {
  625. switch (ProcessorFamily) {
  626. case 5:
  627. switch (ProcessorModel) {
  628. case 4:
  629. VIAProcessor=VIA_PROCESSOR_IDT_C6_WINCHIP;
  630. break;
  631. case 8:
  632. VIAProcessor=VIA_PROCESSOR_IDT_C6_WINCHIP2;
  633. break;
  634. case 9:
  635. VIAProcessor=VIA_PROCESSOR_IDT_C6_WINCHIP3;
  636. break;
  637. }
  638. case 6:
  639. switch (ProcessorModel) {
  640. case 4:
  641. VIAProcessor=VIA_PROCESSOR_CYRIX_III_SAMUEL;
  642. break;
  643. }
  644. }
  645. }
  646. void CPUDetectClass::Init_Rise_Processor_Type()
  647. {
  648. switch (ProcessorFamily) {
  649. case 5:
  650. switch (ProcessorModel) {
  651. case 0:
  652. RiseProcessor=RISE_PROCESSOR_DRAGON_025;
  653. break;
  654. case 2:
  655. RiseProcessor=RISE_PROCESSOR_DRAGON_018;
  656. break;
  657. case 8:
  658. RiseProcessor=RISE_PROCESSOR_DRAGON2_025;
  659. break;
  660. case 9:
  661. RiseProcessor=RISE_PROCESSOR_DRAGON2_018;
  662. break;
  663. }
  664. }
  665. }
  666. void CPUDetectClass::Init_Processor_Family()
  667. {
  668. unsigned signature=0;
  669. unsigned notneeded1;
  670. unsigned notneeded2;
  671. unsigned features;
  672. CPUID(
  673. signature,
  674. notneeded1,
  675. notneeded2,
  676. features,
  677. 1);
  678. ProcessorType=(signature>>12)&0x0f;
  679. ProcessorFamily=(signature>>8)&0x0f;
  680. ProcessorModel=(signature>>4)&0x0f;
  681. ProcessorRevision=(signature)&0x0f;
  682. IntelProcessor=INTEL_PROCESSOR_UNKNOWN;
  683. AMDProcessor=AMD_PROCESSOR_UNKNOWN;
  684. VIAProcessor=VIA_PROCESSOR_UNKNOWN;
  685. RiseProcessor=RISE_PROCESSOR_UNKNOWN;
  686. Init_Cache();
  687. switch (ProcessorManufacturer) {
  688. case MANUFACTURER_INTEL:
  689. Init_Intel_Processor_Type();
  690. break;
  691. case MANUFACTURER_AMD:
  692. Init_AMD_Processor_Type();
  693. break;
  694. case MANUFACTURER_VIA:
  695. Init_VIA_Processor_Type();
  696. break;
  697. case MANUFACTURER_RISE:
  698. Init_Rise_Processor_Type();
  699. break;
  700. }
  701. }
  702. void CPUDetectClass::Init_Processor_String()
  703. {
  704. if (!Has_CPUID_Instruction()) {
  705. ProcessorString[0]='\0';
  706. }
  707. CPUIDStruct ext_id(0x80000000); // Check maximum extended cpuid level
  708. // if (ProcessorManufacturer==MANUFACTURER_INTEL && IntelProcessor<INTEL_PROCESSOR_PENTIUM4) {
  709. // ext_id.Eax=0; // No support for extended cpuid in Intel cpus prior to Pentium4
  710. // }
  711. // If extended cpuid level's highest bit is set, we'll get the cpu string from 2/3/4
  712. if (ext_id.Eax&0x80000000) {
  713. CPUDetectClass::CPUID(
  714. (unsigned&)ProcessorString[0],
  715. (unsigned&)ProcessorString[4],
  716. (unsigned&)ProcessorString[8],
  717. (unsigned&)ProcessorString[12],
  718. 0x80000002);
  719. CPUDetectClass::CPUID(
  720. (unsigned&)ProcessorString[16],
  721. (unsigned&)ProcessorString[20],
  722. (unsigned&)ProcessorString[24],
  723. (unsigned&)ProcessorString[28],
  724. 0x80000003);
  725. CPUDetectClass::CPUID(
  726. (unsigned&)ProcessorString[32],
  727. (unsigned&)ProcessorString[36],
  728. (unsigned&)ProcessorString[40],
  729. (unsigned&)ProcessorString[44],
  730. 0x80000004);
  731. }
  732. // If no extended cpuid available (Intel processors prior to P4), compose the string
  733. else {
  734. StringClass str(0,true);
  735. str=Get_Processor_Manufacturer_Name();
  736. if (ProcessorManufacturer==MANUFACTURER_INTEL) {
  737. str+=" ";
  738. switch (IntelProcessor) {
  739. default:
  740. case INTEL_PROCESSOR_UNKNOWN: str+="<UNKNOWN>"; break;
  741. case INTEL_PROCESSOR_80386: str+="80386"; break;
  742. case INTEL_PROCESSOR_80486DX: str+="80486DX"; break;
  743. case INTEL_PROCESSOR_80486SX: str+="80486SX"; break;
  744. case INTEL_PROCESSOR_80486DX2: str+="80486DX2"; break;
  745. case INTEL_PROCESSOR_80486SL: str+="80486SL"; break;
  746. case INTEL_PROCESSOR_80486SX2: str+="80486SX2"; break;
  747. case INTEL_PROCESSOR_80486DX2_WB: str+="80486DX2(WB)"; break;
  748. case INTEL_PROCESSOR_80486DX4: str+="80486DX4"; break;
  749. case INTEL_PROCESSOR_80486DX4_WB: str+="80486DX4(WB)"; break;
  750. case INTEL_PROCESSOR_PENTIUM: str+="Pentium"; break;
  751. case INTEL_PROCESSOR_PENTIUM_OVERDRIVE: str+="Pentium Overdrive"; break;
  752. case INTEL_PROCESSOR_PENTIUM_MMX: str+="Pentium MMX"; break;
  753. case INTEL_PROCESSOR_PENTIUM_PRO_SAMPLE: str+="Pentium Pro (Engineering Sample)"; break;
  754. case INTEL_PROCESSOR_PENTIUM_PRO: str+="Pentium Pro"; break;
  755. case INTEL_PROCESSOR_PENTIUM_II_OVERDRIVE: str+="Pentium II Overdrive"; break;
  756. case INTEL_PROCESSOR_PENTIUM_II_MODEL_3: str+="Pentium II, model 3"; break;
  757. case INTEL_PROCESSOR_PENTIUM_II_MODEL_4: str+="Pentium II, model 4"; break;
  758. case INTEL_PROCESSOR_CELERON_MODEL_5: str+="Celeron, model 5"; break;
  759. case INTEL_PROCESSOR_PENTIUM_II_MODEL_5: str+="Pentium II, model 5"; break;
  760. case INTEL_PROCESSOR_PENTIUM_II_XEON_MODEL_5: str+="Pentium II Xeon, model 5"; break;
  761. case INTEL_PROCESSOR_CELERON_MODEL_6: str+="Celeron, model 6"; break;
  762. case INTEL_PROCESSOR_PENTIUM_III_MODEL_7: str+="Pentium III, model 7"; break;
  763. case INTEL_PROCESSOR_PENTIUM_III_XEON_MODEL_7: str+="Pentium III Xeon, model 7"; break;
  764. case INTEL_PROCESSOR_CELERON_MODEL_8: str+="Celeron, model 8"; break;
  765. case INTEL_PROCESSOR_PENTIUM_III_MODEL_8: str+="Pentium III, model 8"; break;
  766. case INTEL_PROCESSOR_PENTIUM_III_XEON_MODEL_8: str+="Pentium III Xeon, model 8"; break;
  767. case INTEL_PROCESSOR_PENTIUM_III_XEON_MODEL_A: str+="Pentium III Xeon, model A"; break;
  768. case INTEL_PROCESSOR_PENTIUM_III_MODEL_B: str+="Pentium III, model B"; break;
  769. case INTEL_PROCESSOR_PENTIUM4: str+="Pentium4"; break;
  770. }
  771. }
  772. strncpy(ProcessorString,str.Peek_Buffer(),sizeof(ProcessorString));
  773. }
  774. }
  775. void CPUDetectClass::Init_CPUID_Instruction()
  776. {
  777. unsigned long cpuid_available=0;
  778. // The pushfd/popfd commands are done using emits
  779. // because CodeWarrior seems to have problems with
  780. // the command (huh?)
  781. #ifdef WIN32
  782. __asm
  783. {
  784. mov cpuid_available, 0 // clear flag
  785. push ebx
  786. pushfd
  787. pop eax
  788. mov ebx, eax
  789. xor eax, 0x00200000
  790. push eax
  791. popfd
  792. pushfd
  793. pop eax
  794. xor eax, ebx
  795. je done
  796. mov cpuid_available, 1
  797. done:
  798. push ebx
  799. popfd
  800. pop ebx
  801. }
  802. #elif defined(_UNIX)
  803. __asm__(" mov $0, __cpuid_available"); // clear flag
  804. __asm__(" push %ebx");
  805. __asm__(" pushfd");
  806. __asm__(" pop %eax");
  807. __asm__(" mov %eax, %ebx");
  808. __asm__(" xor 0x00200000, %eax");
  809. __asm__(" push %eax");
  810. __asm__(" popfd");
  811. __asm__(" pushfd");
  812. __asm__(" pop %eax");
  813. __asm__(" xor %ebx, %eax");
  814. __asm__(" je done");
  815. __asm__(" mov $1, __cpuid_available");
  816. goto done; // just to shut the compiler up
  817. done:
  818. __asm__(" push %ebx");
  819. __asm__(" popfd");
  820. __asm__(" pop %ebx");
  821. #endif
  822. HasCPUIDInstruction=!!cpuid_available;
  823. }
  824. void CPUDetectClass::Init_Processor_Features()
  825. {
  826. if (!CPUDetectClass::Has_CPUID_Instruction()) return;
  827. CPUIDStruct id(1);
  828. FeatureBits=id.Edx;
  829. HasRDTSCInstruction=(!!(FeatureBits&(1<<4)));
  830. HasCMOVSupport=(!!(FeatureBits&(1<<15)));
  831. HasMMXSupport=(!!(FeatureBits&(1<<23)));
  832. HasSSESupport=!!(FeatureBits&(1<<25));
  833. HasSSE2Support=!!(FeatureBits&(1<<26));
  834. Has3DNowSupport=false;
  835. ExtendedFeatureBits=0;
  836. if (ProcessorManufacturer==MANUFACTURER_AMD) {
  837. if (Has_CPUID_Instruction()) {
  838. CPUIDStruct max_ext_id(0x80000000);
  839. if (max_ext_id.Eax>=0x80000001) { // Signature & features field available?
  840. CPUIDStruct ext_signature(0x80000001);
  841. ExtendedFeatureBits=ext_signature.Edx;
  842. Has3DNowSupport=!!(ExtendedFeatureBits&0x80000000);
  843. HasExtended3DNowSupport=!!(ExtendedFeatureBits&0x40000000);
  844. }
  845. }
  846. }
  847. }
  848. void CPUDetectClass::Init_Memory()
  849. {
  850. #ifdef WIN32
  851. MEMORYSTATUS mem;
  852. GlobalMemoryStatus(&mem);
  853. TotalPhysicalMemory = mem.dwTotalPhys;
  854. AvailablePhysicalMemory = mem.dwAvailPhys;
  855. TotalPageMemory = mem.dwTotalPageFile;
  856. AvailablePageMemory = mem.dwAvailPageFile;
  857. TotalVirtualMemory = mem.dwTotalVirtual;
  858. AvailableVirtualMemory = mem.dwAvailVirtual;
  859. #elif defined(_UNIX)
  860. #warning FIX Init_Memory()
  861. #endif
  862. }
  863. void CPUDetectClass::Init_OS()
  864. {
  865. OSVERSIONINFO os;
  866. #ifdef WIN32
  867. os.dwOSVersionInfoSize = sizeof(os);
  868. GetVersionEx(&os);
  869. OSVersionNumberMajor = os.dwMajorVersion;
  870. OSVersionNumberMinor = os.dwMinorVersion;
  871. OSVersionBuildNumber = os.dwBuildNumber;
  872. OSVersionPlatformId = os.dwPlatformId;
  873. OSVersionExtraInfo = os.szCSDVersion;
  874. #elif defined(_UNIX)
  875. #warning FIX Init_OS()
  876. #endif
  877. }
  878. bool CPUDetectClass::CPUID(
  879. unsigned& u_eax_,
  880. unsigned& u_ebx_,
  881. unsigned& u_ecx_,
  882. unsigned& u_edx_,
  883. unsigned cpuid_type)
  884. {
  885. if (!Has_CPUID_Instruction()) return false; // Most processors since 486 have CPUID...
  886. unsigned u_eax;
  887. unsigned u_ebx;
  888. unsigned u_ecx;
  889. unsigned u_edx;
  890. #ifdef WIN32
  891. __asm
  892. {
  893. pushad
  894. mov eax, [cpuid_type]
  895. xor ebx, ebx
  896. xor ecx, ecx
  897. xor edx, edx
  898. cpuid
  899. mov [u_eax], eax
  900. mov [u_ebx], ebx
  901. mov [u_ecx], ecx
  902. mov [u_edx], edx
  903. popad
  904. }
  905. #elif defined(_UNIX)
  906. __asm__("pusha");
  907. __asm__("mov __cpuid_type, %eax");
  908. __asm__("xor %ebx, %ebx");
  909. __asm__("xor %ecx, %ecx");
  910. __asm__("xor %edx, %edx");
  911. __asm__("cpuid");
  912. __asm__("mov %eax, __u_eax");
  913. __asm__("mov %ebx, __u_ebx");
  914. __asm__("mov %ecx, __u_ecx");
  915. __asm__("mov %edx, __u_edx");
  916. __asm__("popa");
  917. #endif
  918. u_eax_=u_eax;
  919. u_ebx_=u_ebx;
  920. u_ecx_=u_ecx;
  921. u_edx_=u_edx;
  922. return true;
  923. }
  924. #define SYSLOG(n) work.Format n ; CPUDetectClass::ProcessorLog+=work;
  925. void CPUDetectClass::Init_Processor_Log()
  926. {
  927. StringClass work(0,true);
  928. SYSLOG(("Operating System: "));
  929. switch (OSVersionPlatformId) {
  930. case VER_PLATFORM_WIN32s: SYSLOG(("Windows 3.1")); break;
  931. case VER_PLATFORM_WIN32_WINDOWS: SYSLOG(("Windows 9x")); break;
  932. case VER_PLATFORM_WIN32_NT: SYSLOG(("Windows NT")); break;
  933. }
  934. SYSLOG(("\r\n"));
  935. SYSLOG(("Operating system version %d.%d\r\n",OSVersionNumberMajor,OSVersionNumberMinor));
  936. SYSLOG(("Operating system build: %d.%d.%d\r\n",
  937. (OSVersionBuildNumber&0xff000000)>>24,
  938. (OSVersionBuildNumber&0xff0000)>>16,
  939. (OSVersionBuildNumber&0xffff)));
  940. #ifdef WIN32
  941. SYSLOG(("OS-Info: %s\r\n", OSVersionExtraInfo));
  942. #elif defined(_UNIX)
  943. SYSLOG(("OS-Info: %s\r\n", OSVersionExtraInfo.Peek_Buffer()));
  944. #endif
  945. SYSLOG(("Processor: %s\r\n",CPUDetectClass::Get_Processor_String()));
  946. SYSLOG(("Clock speed: ~%dMHz\r\n",CPUDetectClass::Get_Processor_Speed()));
  947. StringClass cpu_type(0,true);
  948. switch (CPUDetectClass::Get_Processor_Type()) {
  949. case 0: cpu_type="Original OEM"; break;
  950. case 1: cpu_type="Overdrive"; break;
  951. case 2: cpu_type="Dual"; break;
  952. case 3: cpu_type="*Intel Reserved*"; break;
  953. }
  954. #ifdef WIN32
  955. SYSLOG(("Processor type: %s\r\n", cpu_type));
  956. #elif defined(_UNIX)
  957. SYSLOG(("Processor type: %s\r\n", cpu_type.Peek_Buffer()));
  958. #endif
  959. SYSLOG(("\r\n"));
  960. SYSLOG(("Total physical memory: %dMb\r\n",Get_Total_Physical_Memory()/(1024*1024)));
  961. SYSLOG(("Available physical memory: %dMb\r\n",Get_Available_Physical_Memory()/(1024*1024)));
  962. SYSLOG(("Total page file size: %dMb\r\n",Get_Total_Page_File_Size()/(1024*1024)));
  963. SYSLOG(("Total available page file size: %dMb\r\n",Get_Available_Page_File_Size()/(1024*1024)));
  964. SYSLOG(("Total virtual memory: %dMb\r\n",Get_Total_Virtual_Memory()/(1024*1024)));
  965. SYSLOG(("Available virtual memory: %dMb\r\n",Get_Available_Virtual_Memory()/(1024*1024)));
  966. SYSLOG(("\r\n"));
  967. SYSLOG(("CPUID: %s\r\n",CPUDetectClass::Has_CPUID_Instruction() ? "Yes" : "No"));
  968. SYSLOG(("RDTSC: %s\r\n",CPUDetectClass::Has_RDTSC_Instruction() ? "Yes" : "No"));
  969. SYSLOG(("CMOV: %s\r\n",CPUDetectClass::Has_CMOV_Instruction() ? "Yes" : "No"));
  970. SYSLOG(("MMX: %s\r\n",CPUDetectClass::Has_MMX_Instruction_Set() ? "Yes" : "No"));
  971. SYSLOG(("SSE: %s\r\n",CPUDetectClass::Has_SSE_Instruction_Set() ? "Yes" : "No"));
  972. SYSLOG(("SSE2: %s\r\n",CPUDetectClass::Has_SSE2_Instruction_Set() ? "Yes" : "No"));
  973. SYSLOG(("3DNow!: %s\r\n",CPUDetectClass::Has_3DNow_Instruction_Set() ? "Yes" : "No"));
  974. SYSLOG(("Extended 3DNow!: %s\r\n",CPUDetectClass::Has_Extended_3DNow_Instruction_Set() ? "Yes" : "No"));
  975. SYSLOG(("CPU Feature bits: 0x%x\r\n",CPUDetectClass::Get_Feature_Bits()));
  976. SYSLOG(("Ext. CPU Feature bits: 0x%x\r\n",CPUDetectClass::Get_Extended_Feature_Bits()));
  977. SYSLOG(("\r\n"));
  978. if (CPUDetectClass::Get_L1_Data_Cache_Size()) {
  979. SYSLOG(("L1 Data Cache: %d byte cache lines, %d way set associative, %dk\r\n",
  980. CPUDetectClass::Get_L1_Data_Cache_Line_Size(),
  981. CPUDetectClass::Get_L1_Data_Cache_Set_Associative(),
  982. CPUDetectClass::Get_L1_Data_Cache_Size()/1024));
  983. }
  984. else {
  985. SYSLOG(("L1 Data Cache: None\r\n"));
  986. }
  987. if (CPUDetectClass::Get_L1_Instruction_Cache_Size()) {
  988. SYSLOG(("L1 Instruction Cache: %d byte cache lines, %d way set associative, %dk\r\n",
  989. CPUDetectClass::Get_L1_Instruction_Cache_Line_Size(),
  990. CPUDetectClass::Get_L1_Instruction_Cache_Set_Associative(),
  991. CPUDetectClass::Get_L1_Instruction_Cache_Size()/1024));
  992. }
  993. else {
  994. SYSLOG(("L1 Instruction Cache: None\r\n"));
  995. }
  996. if (CPUDetectClass::Get_L1_Instruction_Trace_Cache_Size()) {
  997. SYSLOG(("L1 Instruction Trace Cache: %d way set associative, %dk µOPs\r\n",
  998. CPUDetectClass::Get_L1_Instruction_Cache_Set_Associative(),
  999. CPUDetectClass::Get_L1_Instruction_Cache_Size()/1024));
  1000. }
  1001. else {
  1002. SYSLOG(("L1 Instruction Trace Cache: None\r\n"));
  1003. }
  1004. if (CPUDetectClass::Get_L2_Cache_Size()) {
  1005. SYSLOG(("L2 Cache: %d byte cache lines, %d way set associative, %dk\r\n",
  1006. CPUDetectClass::Get_L2_Cache_Line_Size(),
  1007. CPUDetectClass::Get_L2_Cache_Set_Associative(),
  1008. CPUDetectClass::Get_L2_Cache_Size()/1024));
  1009. }
  1010. else {
  1011. SYSLOG(("L2 cache: None\r\n"));
  1012. }
  1013. SYSLOG(("\r\n"));
  1014. }
  1015. // OSCODE OSSUBCODE CPUMANUFACTURER CPUSPEED MEMORY CPUBITS EXTCPUBITS
  1016. #define COMPACTLOG(n) work.Format n ; CPUDetectClass::CompactLog+=work;
  1017. void CPUDetectClass::Init_Compact_Log()
  1018. {
  1019. StringClass work(0,true);
  1020. #ifdef WIN32
  1021. TIME_ZONE_INFORMATION time_zone;
  1022. GetTimeZoneInformation(&time_zone);
  1023. COMPACTLOG(("%d\t", time_zone.Bias)); // get diff between local time and UTC
  1024. #elif defined(_UNIX)
  1025. time_t t = time(NULL);
  1026. localtime(&t);
  1027. COMPACTLOG(("%d\t", timezone));
  1028. #endif
  1029. OSInfoStruct os_info;
  1030. Get_OS_Info(os_info,OSVersionPlatformId,OSVersionNumberMajor,OSVersionNumberMinor,OSVersionBuildNumber);
  1031. COMPACTLOG(("%s\t",os_info.Code));
  1032. if (!stricmp(os_info.SubCode,"UNKNOWN")) {
  1033. COMPACTLOG(("%d\t",OSVersionBuildNumber&0xffff));
  1034. }
  1035. else {
  1036. COMPACTLOG(("%s\t",os_info.SubCode));
  1037. }
  1038. COMPACTLOG(("%s\t%d\t",Get_Processor_Manufacturer_Name(),Get_Processor_Speed()));
  1039. COMPACTLOG(("%d\t",Get_Total_Physical_Memory()/(1024*1024)+1));
  1040. COMPACTLOG(("%x\t%x\t",Get_Feature_Bits(),Get_Extended_Feature_Bits()));
  1041. }
  1042. static class CPUDetectInitClass
  1043. {
  1044. public:
  1045. CPUDetectInitClass::CPUDetectInitClass()
  1046. {
  1047. CPUDetectClass::Init_CPUID_Instruction();
  1048. // We pretty much need CPUID, but let's not crash if it doesn't exist.
  1049. // Every processor our games run should have CPUID so it would be extremely unlikely for it not to be present.
  1050. // One can never be sure about the clones though...
  1051. if (CPUDetectClass::Has_CPUID_Instruction()) {
  1052. CPUDetectClass::Init_Processor_Manufacturer();
  1053. CPUDetectClass::Init_Processor_Family();
  1054. CPUDetectClass::Init_Processor_String();
  1055. CPUDetectClass::Init_Processor_Features();
  1056. CPUDetectClass::Init_Memory();
  1057. CPUDetectClass::Init_OS();
  1058. }
  1059. CPUDetectClass::Init_Processor_Speed();
  1060. CPUDetectClass::Init_Processor_Log();
  1061. CPUDetectClass::Init_Compact_Log();
  1062. }
  1063. } _CPU_Detect_Init;
  1064. OSInfoStruct Windows9xVersionTable[]={
  1065. {"WIN95", "FINAL", "Windows 95", 4,0,950, 4,0,950 },
  1066. {"WIN95", "A", "Windows 95a OSR1 final Update", 4,0,950, 4,0,951 },
  1067. {"WIN95", "B20OEM", "Windows 95B OSR 2.0 final OEM", 4,0,950, 4,0,1111 },
  1068. {"WIN95", "B20UPD", "Windows 95B OSR 2.1 final Update", 4,0,950, 4,3,1212 },
  1069. {"WIN95", "B21OEM", "Windows 95B OSR 2.1 final OEM", 4,1,971, 4,1,971 },
  1070. {"WIN95", "C25OEM", "Windows 95C OSR 2.5 final OEM", 4,0,950, 4,3,1214 },
  1071. {"WIN98", "BETAPRD", "Windows 98 Beta pre-DR", 4,10,1351, 4,10,1351 },
  1072. {"WIN98", "BETADR", "Windows 98 Beta DR", 4,10,1358, 4,10,1358 },
  1073. {"WIN98", "BETAE", "Windows 98 early Beta", 4,10,1378, 4,10,1378 },
  1074. {"WIN98", "BETAE", "Windows 98 early Beta", 4,10,1410, 4,10,1410 },
  1075. {"WIN98", "BETAE", "Windows 98 early Beta", 4,10,1423, 4,10,1423 },
  1076. {"WIN98", "BETA1", "Windows 98 Beta 1", 4,10,1500, 4,10,1500 },
  1077. {"WIN98", "BETA1", "Windows 98 Beta 1", 4,10,1508, 4,10,1508 },
  1078. {"WIN98", "BETA1", "Windows 98 Beta 1", 4,10,1511, 4,10,1511 },
  1079. {"WIN98", "BETA1", "Windows 98 Beta 1", 4,10,1525, 4,10,1525 },
  1080. {"WIN98", "BETA1", "Windows 98 Beta 1", 4,10,1535, 4,10,1535 },
  1081. {"WIN98", "BETA1", "Windows 98 Beta 1", 4,10,1538, 4,10,1538 },
  1082. {"WIN98", "BETA1", "Windows 98 Beta 1", 4,10,1543, 4,10,1543 },
  1083. {"WIN98", "BETA2", "Windows 98 Beta 2", 4,10,1544, 4,10,1544 },
  1084. {"WIN98", "BETA2", "Windows 98 Beta 2", 4,10,1546, 4,10,1546 },
  1085. {"WIN98", "BETA2", "Windows 98 Beta 2", 4,10,1550, 4,10,1550 },
  1086. {"WIN98", "BETA2", "Windows 98 Beta 2", 4,10,1559, 4,10,1559 },
  1087. {"WIN98", "BETA2", "Windows 98 Beta 2", 4,10,1564, 4,10,1564 },
  1088. {"WIN98", "BETA2", "Windows 98 Beta 2", 4,10,1569, 4,10,1569 },
  1089. {"WIN98", "BETA2", "Windows 98 Beta 2", 4,10,1577, 4,10,1577 },
  1090. {"WIN98", "BETA2", "Windows 98 Beta 2", 4,10,1581, 4,10,1581 },
  1091. {"WIN98", "BETA2", "Windows 98 Beta 2", 4,10,1593, 4,10,1593 },
  1092. {"WIN98", "BETA2", "Windows 98 Beta 2", 4,10,1599, 4,10,1599 },
  1093. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1602, 4,10,1602 },
  1094. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1605, 4,10,1605 },
  1095. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1614, 4,10,1614 },
  1096. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1619, 4,10,1619 },
  1097. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1624, 4,10,1624 },
  1098. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1629, 4,10,1629 },
  1099. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1633, 4,10,1633 },
  1100. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1650, 4,10,1650 },
  1101. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1650,/*,3*/4,10,1650/*,3*/ },
  1102. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1650,/*,8*/4,10,1650/*,8*/ },
  1103. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1666, 4,10,1666 },
  1104. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1671, 4,10,1671 },
  1105. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1677, 4,10,1677 },
  1106. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1681, 4,10,1681 },
  1107. {"WIN98", "BETA3", "Windows 98 Beta 3", 4,10,1687, 4,10,1687 },
  1108. {"WIN98", "RC0", "Windows 98 RC0", 4,10,1691, 4,10,1691 },
  1109. {"WIN98", "RC0", "Windows 98 RC0", 4,10,1702, 4,10,1702 },
  1110. {"WIN98", "RC0", "Windows 98 RC0", 4,10,1708, 4,10,1708 },
  1111. {"WIN98", "RC0", "Windows 98 RC0", 4,10,1713, 4,10,1713 },
  1112. {"WIN98", "RC1", "Windows 98 RC1", 4,10,1721,/*,3*/4,10,1721/*,3*/ },
  1113. {"WIN98", "RC2", "Windows 98 RC2", 4,10,1723,/*,4*/4,10,1723/*,4*/ },
  1114. {"WIN98", "RC2", "Windows 98 RC2", 4,10,1726, 4,10,1726 },
  1115. {"WIN98", "RC3", "Windows 98 RC3", 4,10,1900,/*,5*/4,10,1900/*,5*/ },
  1116. {"WIN98", "RC4", "Windows 98 RC4", 4,10,1900,/*,8*/4,10,1900/*,8*/ },
  1117. {"WIN98", "RC5", "Windows 98 RC5", 4,10,1998, 4,10,1998 },
  1118. {"WIN98", "FINAL", "Windows 98", 4,10,1998,/*,6*/4,10,1998/*,6*/ },
  1119. {"WIN98", "SP1B1", "Windows 98 SP1 Beta 1", 4,10,2088, 4,10,2088 },
  1120. {"WIN98", "OSR1B1", "Windows 98 OSR1 Beta 1", 4,10,2106, 4,10,2106 },
  1121. {"WIN98", "OSR1B1", "Windows 98 OSR1 Beta 1", 4,10,2120, 4,10,2120 },
  1122. {"WIN98", "OSR1B1", "Windows 98 OSR1 Beta 1", 4,10,2126, 4,10,2126 },
  1123. {"WIN98", "OSR1B1", "Windows 98 OSR1 Beta 1", 4,10,2131, 4,10,2131 },
  1124. {"WIN98", "SP1B2", "Windows 98 SP1 Beta 2", 4,10,2150,/*,0*/4,10,2150/*,0*/ },
  1125. {"WIN98", "SP1B2", "Windows 98 SP1 Beta 2", 4,10,2150,/*,4*/4,10,2150/*,4*/ },
  1126. {"WIN98", "SP1", "Windows 98 SP1 final Update", 4,10,2000, 4,10,2000 },
  1127. {"WIN98", "OSR1B2", "Windows 98 OSR1 Beta 2", 4,10,2174, 4,10,2174 },
  1128. {"WIN98", "SERC1", "Windows 98 SE RC1", 4,10,2183, 4,10,2183 },
  1129. {"WIN98", "SERC2", "Windows 98 SE RC2", 4,10,2185, 4,10,2185 },
  1130. {"WIN98", "SE", "Windows 98 SE", 4,10,2222, 4,10,2222/*,3*/ },
  1131. {"WINME", "MEBDR1", "Windows ME Beta DR1", 4,90,2332, 4,90,2332 },
  1132. {"WINME", "MEBDR2", "Windows ME Beta DR2", 4,90,2348, 4,90,2348 },
  1133. {"WINME", "MEBDR3", "Windows ME Beta DR3", 4,90,2358, 4,90,2358 },
  1134. {"WINME", "MEBDR4", "Windows ME Beta DR4", 4,90,2363, 4,90,2363 },
  1135. {"WINME", "MEEB", "Windows ME early Beta", 4,90,2368, 4,90,2368 },
  1136. {"WINME", "MEEB", "Windows ME early Beta", 4,90,2374, 4,90,2374 },
  1137. {"WINME", "MEB1", "Windows ME Beta 1", 4,90,2380, 4,90,2380 },
  1138. {"WINME", "MEB1", "Windows ME Beta 1", 4,90,2394, 4,90,2394 },
  1139. {"WINME", "MEB1", "Windows ME Beta 1", 4,90,2399, 4,90,2399 },
  1140. {"WINME", "MEB1", "Windows ME Beta 1", 4,90,2404, 4,90,2404 },
  1141. {"WINME", "MEB1", "Windows ME Beta 1", 4,90,2410, 4,90,2410 },
  1142. {"WINME", "MEB1", "Windows ME Beta 1", 4,90,2416, 4,90,2416 },
  1143. {"WINME", "MEB1", "Windows ME Beta 1", 4,90,2419,/*,4*/4,90,2419/*,4*/ },
  1144. {"WINME", "MEB2", "Windows ME Beta 2", 4,90,2429, 4,90,2429 },
  1145. {"WINME", "MEB2", "Windows ME Beta 2", 4,90,2434, 4,90,2434 },
  1146. {"WINME", "MEB2", "Windows ME Beta 2", 4,90,2443, 4,90,2443 },
  1147. {"WINME", "MEB2", "Windows ME Beta 2", 4,90,2447, 4,90,2447 },
  1148. {"WINME", "MEB2", "Windows ME Beta 2", 4,90,2455, 4,90,2455 },
  1149. {"WINME", "MEB2", "Windows ME Beta 2", 4,90,2460, 4,90,2460 },
  1150. {"WINME", "MEB2", "Windows ME Beta 2", 4,90,2465, 4,90,2465 },
  1151. {"WINME", "MEB2", "Windows ME Beta 2", 4,90,2470, 4,90,2470 },
  1152. {"WINME", "MEB2", "Windows ME Beta 2", 4,90,2474, 4,90,2474 },
  1153. {"WINME", "MEB2", "Windows ME Beta 2", 4,90,2481, 4,90,2481 },
  1154. {"WINME", "MEB2", "Windows ME Beta 2", 4,90,2487, 4,90,2487 },
  1155. {"WINME", "MEB2", "Windows ME Beta 2", 4,90,2491, 4,90,2491 },
  1156. {"WINME", "MEB3", "Windows ME Beta 3", 4,90,2499, 4,90,2499 },
  1157. {"WINME", "MEB3", "Windows ME Beta 3", 4,90,2499,/*,3*/4,90,2499/*,3*/ },
  1158. {"WINME", "MEB3", "Windows ME Beta 3", 4,90,2509, 4,90,2509 },
  1159. {"WINME", "MEB3", "Windows ME Beta 3", 4,90,2513, 4,90,2513 },
  1160. {"WINME", "MEB3", "Windows ME Beta 3", 4,90,2516, 4,90,2516 },
  1161. {"WINME", "RC0", "Windows ME RC0", 4,90,2525, 4,90,2525 },
  1162. {"WINME", "RC1", "Windows ME RC1", 4,90,2525,/*,6*/4,90,2525/*,6*/ },
  1163. {"WINME", "RC2", "Windows ME RC2", 4,90,2535, 4,90,2535 },
  1164. {"WINME", "FINAL", "Windows ME", 4,90,3000,/*,2*/4,90,3000/*,2*/ },
  1165. };
  1166. void Get_OS_Info(
  1167. OSInfoStruct& os_info,
  1168. unsigned OSVersionPlatformId,
  1169. unsigned OSVersionNumberMajor,
  1170. unsigned OSVersionNumberMinor,
  1171. unsigned OSVersionBuildNumber)
  1172. {
  1173. unsigned build_major=(OSVersionBuildNumber&0xff000000)>>24;
  1174. unsigned build_minor=(OSVersionBuildNumber&0xff0000)>>16;
  1175. unsigned build_sub=(OSVersionBuildNumber&0xffff);
  1176. switch (OSVersionPlatformId) {
  1177. default:
  1178. memset(&os_info,0,sizeof(os_info));
  1179. os_info.Code="UNKNOWN";
  1180. os_info.SubCode="UNKNOWN";
  1181. os_info.VersionString="UNKNOWN";
  1182. break;
  1183. case VER_PLATFORM_WIN32_WINDOWS:
  1184. {
  1185. for(int i=0;i<sizeof(Windows9xVersionTable)/sizeof(os_info);++i) {
  1186. if (
  1187. Windows9xVersionTable[i].VersionMajor==OSVersionNumberMajor &&
  1188. Windows9xVersionTable[i].VersionMinor==OSVersionNumberMinor &&
  1189. Windows9xVersionTable[i].BuildMajor==build_major &&
  1190. Windows9xVersionTable[i].BuildMinor==build_minor &&
  1191. Windows9xVersionTable[i].BuildSub==build_sub) {
  1192. os_info=Windows9xVersionTable[i];
  1193. return;
  1194. }
  1195. }
  1196. os_info.BuildMajor=build_major;
  1197. os_info.BuildMinor=build_minor;
  1198. os_info.BuildSub=build_sub;
  1199. if (OSVersionNumberMajor==4) {
  1200. // os_info.SubCode.Format("%d",build_sub);
  1201. os_info.SubCode="UNKNOWN";
  1202. if (OSVersionNumberMinor==0) {
  1203. os_info.Code="WIN95";
  1204. return;
  1205. }
  1206. if (OSVersionNumberMinor==10) {
  1207. os_info.Code="WIN98";
  1208. return;
  1209. }
  1210. if (OSVersionNumberMinor==90) {
  1211. os_info.Code="WINME";
  1212. return;
  1213. }
  1214. os_info.Code="WIN9X";
  1215. return;
  1216. }
  1217. }
  1218. break;
  1219. case VER_PLATFORM_WIN32_NT:
  1220. // os_info.SubCode.Format("%d",build_sub);
  1221. os_info.SubCode="UNKNOWN";
  1222. if (OSVersionNumberMajor==4) {
  1223. os_info.Code="WINNT";
  1224. return;
  1225. }
  1226. if (OSVersionNumberMajor==5) {
  1227. if (OSVersionNumberMinor==0) {
  1228. os_info.Code="WIN2K";
  1229. return;
  1230. }
  1231. if (OSVersionNumberMinor==1) {
  1232. os_info.Code="WINXP";
  1233. return;
  1234. }
  1235. os_info.Code="WINXX";
  1236. return;
  1237. }
  1238. }
  1239. }