cpudetect.cpp 41 KB

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