openMSX
HostCPU.cc
Go to the documentation of this file.
1 #include "HostCPU.hh"
2 #include "openmsx.hh"
3 #include <cassert>
4 #ifdef _MSC_VER
5 #include <intrin.h>
6 #endif
7 
8 namespace HostCPU {
9 
10 // Initially assume no CPU feature support
11 bool mmxFlag = false;
12 bool sseFlag = false;
13 bool sse2Flag = false;
14 
15 /*static*/ // to avoid 'unsused static function' compiler warning on x86_64
16 void setFeatures(unsigned features)
17 {
18  const unsigned CPUID_FEATURE_MMX = 0x00800000;
19  const unsigned CPUID_FEATURE_SSE = 0x02000000;
20  const unsigned CPUID_FEATURE_SSE2 = 0x04000000;
21 
22  mmxFlag = (features & CPUID_FEATURE_MMX) != 0;
23  sseFlag = (features & CPUID_FEATURE_SSE) != 0;
24  sse2Flag = (features & CPUID_FEATURE_SSE2) != 0;
25 }
26 
27 void init()
28 {
29  #ifdef __x86_64
30  // X86_64 machines always have mmx, sse, sse2
31  mmxFlag = true;
32  sseFlag = true;
33  sse2Flag = true;
34  #elif ASM_X86_32
35  #ifdef _MSC_VER
36  unsigned hasCPUID;
37  __asm {
38  // Load EFLAGS into EAX
39  pushfd
40  pop eax
41  // Save current value.
42  mov ecx,eax
43  // Toggle bit 21.
44  xor eax,200000h
45  // Load EAX into EFLAGS.
46  push eax
47  popfd
48  // Load EFLAGS into EAX.
49  pushfd
50  pop eax
51  // Did bit 21 change?
52  xor eax,ecx
53  and eax,200000h
54  mov hasCPUID,eax
55  }
56  if (hasCPUID) {
57  int cpuInfo[4];
58  __cpuid(cpuInfo, 0);
59  if (cpuInfo[0] >= 1) {
60  __cpuid(cpuInfo, 1);
61  setFeatures(cpuInfo[3]);
62  }
63  }
64  #else
65  // Note: On Mac OS X, EBX is in use by the OS,
66  // so we have to restore it.
67  // Is CPUID instruction supported?
68  unsigned hasCPUID;
69  asm (
70  // Load EFLAGS into EAX.
71  "pushfl;"
72  "popl %%eax;"
73  // Save current value.
74  "movl %%eax,%%ecx;"
75  // Toggle bit 21.
76  "xorl $0x200000, %%eax;"
77  // Load EAX into EFLAGS.
78  "pushl %%eax;"
79  "popfl;"
80  // Load EFLAGS into EAX.
81  "pushfl;"
82  "popl %%eax;"
83  // Did bit 21 change?
84  "xor %%ecx, %%eax;"
85  "andl $0x200000, %%eax;"
86  : "=a" (hasCPUID) // 0
87  : // no input
88  : "ecx"
89  );
90  if (hasCPUID) {
91  // Which CPUID calls are supported?
92  unsigned highest;
93  asm (
94  "pushl %%ebx;"
95  "cpuid;"
96  "popl %%ebx;"
97  : "=a" (highest) // 0
98  : "0" (0) // 1: function
99  : "ecx", "edx"
100  );
101  if (highest >= 1) {
102  // Get features flags.
103  unsigned features;
104  asm (
105  "pushl %%ebx;"
106  "cpuid;"
107  "popl %%ebx;"
108  : "=d" (features) // 0
109  : "a" (1) // 1: function
110  : "ecx"
111  );
112  setFeatures(features);
113  }
114  }
115  #endif
116  #endif
117 
118  PRT_DEBUG("MMX: " << mmxFlag);
119  PRT_DEBUG("SSE: " << sseFlag);
120  PRT_DEBUG("SSE2: " << sse2Flag);
121 
122  if (hasSSE2()) { assert(hasMMX() && hasSSE()); }
123  if (hasSSE()) { assert(hasMMX()); }
124 }
125 
126 } // namespace openmsx