1 module xbyak_cpuid;
2 import std.stdio;
3 
4 alias uint64 = ulong;
5 enum  Type : uint64 {
6 	NONE          = 0,
7 	tMMX          = 1 << 0,     //mmx(), //amdMmx()
8 	tMMX2         = 1 << 1,
9 	tCMOV         = 1 << 2,     //hasCmov()
10 	tSSE          = 1 << 3,     //sse()
11 	tSSE2         = 1 << 4,     //sse2()
12 	tSSE3         = 1 << 5,     //sse3()
13 	tSSSE3        = 1 << 6,     //ssse3()
14 	tSSE41        = 1 << 7,     //sse41()
15 	tSSE42        = 1 << 8,     //sse42()
16 	tPOPCNT       = 1 << 9,     //hasPopcnt()
17 	tAESNI        = 1 << 10,    //aes()
18 	tSSE5         = 1 << 11,    //??
19 	tOSXSAVE      = 1 << 12,    //OSXSAVE_BIT
20 	tPCLMULQDQ    = 1 << 13,    //hasPclmulqdq()
21 	tAVX          = 1 << 14,    //avx()
22 	tFMA          = 1 << 15,    //fma()
23 
24 	t3DN          = 1 << 16,    //amd3dnow()
25 	tE3DN         = 1 << 17,    //amd3dnowExt()
26 	tSSE4a        = 1 << 18,    //sse4a()
27 	tRDTSCP       = 1 << 19,    //RDTSCP_BIT
28 	tAVX2         = 1 << 20,    //avx2()
29 	tBMI1         = 1 << 21,    //andn, bextr, blsi, blsmsk, blsr, tzcnt //BMI1_BIT
30 	tBMI2         = 1 << 22,    //bzhi, mulx, pdep, pext, rorx, sarx, shlx, shrx //BMI2_BIT
31 	tLZCNT        = 1 << 23,    //hasLzcnt()
32 
33 	tINTEL        = 1 << 24,
34 	tAMD          = 1 << 25,
35 
36 	tENHANCED_REP = 1 << 26,            //enhanced rep movsb/stosb //ERMS_BIT
37 	tRDRAND       = 1 << 27,            //hasRdrand()
38 	tADX          = 1 << 28,            //adcx, adox //EAX=7 bit<<19
39 	tRDSEED       = 1 << 29,            //rdseed //hasRdseed()
40 	tSMAP         = 1 << 30,            //stac //EAX=7 bit<<20
41 	tHLE          = 1 << 31,            //xacquire, xrelease, xtest //hle()
42 	tRTM          = uint64(1) << 32,    //xbegin, xend, xabort //rtm()
43 	tF16C         = uint64(1) << 33,    //vcvtph2ps, vcvtps2ph //fp16c()
44 	tMOVBE        = uint64(1) << 34     //mobve //bit<22
45 }
46 
47 class CpuId {
48 	uint64 type_;
49 	uint get32bitAsBE(string x)
50 	{
51 		return (x[0] | (x[1] << 8) | (x[2] << 16) | (x[3] << 24));
52 	}
53 
54 	uint mask(int n)
55 	{
56 		return ((1U << n) - 1);
57 	}
58 
59 	void setFamily()
60 	{
61 		uint[4] data;
62 
63 		data = getCpuid(1);
64 		stepping = data[0] & mask(4);
65 		model = (data[0] >> 4) & mask(4);
66 		family = (data[0] >> 8) & mask(4);
67 		// type = (data[0] >> 12) & mask(2);
68 		extModel = (data[0] >> 16) & mask(4);
69 		extFamily = (data[0] >> 20) & mask(8);
70 		if (family == 0x0f) {
71 			displayFamily = family + extFamily;
72 		}else {
73 			displayFamily = family;
74 		}
75 		if ((family == 6) || (family == 0x0f)) {
76 			displayModel = (extModel << 4) + model;
77 		}else {
78 			displayModel = model;
79 		}
80 	}
81 
82 public:
83 	int model;
84 	int family;
85 	int stepping;
86 	int extModel;
87 	int extFamily;
88 	int displayFamily;      // family + extFamily
89 	int displayModel;       // model + extModel
90 
91 	uint[4] getCpuid(uint eaxIn)
92 	{
93 		uint d1, d2, d3, d4;
94 		asm
95 		{
96 			mov EAX, eaxIn;
97 			cpuid;
98 			mov d1, EAX;
99 			mov d2, EBX;
100 			mov d3, ECX;
101 			mov d4, EDX;
102 		}
103 		return [d1, d2, d3, d4];
104 	}
105 
106 	uint[4] getCpuidEx(uint eaxIn, uint ecxIn)
107 	{
108 		uint d1, d2, d3, d4;
109 		asm
110 		{
111 			mov EAX, eaxIn;
112 			mov ECX, ecxIn;
113 			cpuid;
114 			mov d1, EAX;
115 			mov d2, EBX;
116 			mov d3, ECX;
117 			mov d4, EDX;
118 		}
119 		return [d1, d2, d3, d4];
120 	}
121 
122 	uint64 getXfeature()
123 	{
124 		uint d, a;
125 		asm
126 		{
127 			mov ECX, 0;
128 			xgetbv;
129 			mov d, EDX;
130 			mov a, EAX;
131 		}
132 		return (cast(uint64) d << 32 | a);
133 	}
134 
135 	this()
136 	{
137 		type_ = Type.NONE;
138 		uint[4] data;
139 		data = getCpuid(0);
140 		uint maxNum = data[0];
141 		string intel = "ntel";
142 		string amd = "cAMD";
143 		if (data[2] == get32bitAsBE(amd)) {
144 			type_ |= Type.tAMD;
145 			data = getCpuid(0x80000001);
146 			if (data[3] & (1U << 31)) {
147 				type_ |= Type.t3DN;
148 			}
149 			if (data[3] & (1U << 15)) {
150 				type_ |= Type.tCMOV;
151 			}
152 			if (data[3] & (1U << 30)) {
153 				type_ |= Type.tE3DN;
154 			}
155 			if (data[3] & (1U << 22)) {
156 				type_ |= Type.tMMX2;
157 			}
158 			if (data[3] & (1U << 27)) {
159 				type_ |= Type.tRDTSCP;
160 			}
161 		}
162 		if (data[2] == get32bitAsBE(intel)) {
163 			type_ |= Type.tINTEL;
164 			data = getCpuid(0x80000001);
165 			if (data[3] & (1U << 27)) {
166 				type_ |= Type.tRDTSCP;
167 			}
168 			if (data[2] & (1U << 5)) {
169 				type_ |= Type.tLZCNT;
170 			}
171 		}
172 		data = getCpuid(1);
173 		if (data[2] & (1U << 0)) {
174 			type_ |= Type.tSSE3;
175 		}
176 		if (data[2] & (1U << 9)) {
177 			type_ |= Type.tSSSE3;
178 		}
179 		if (data[2] & (1U << 19)) {
180 			type_ |= Type.tSSE41;
181 		}
182 		if (data[2] & (1U << 20)) {
183 			type_ |= Type.tSSE42;
184 		}
185 		if (data[2] & (1U << 22)) {
186 			type_ |= Type.tMOVBE;
187 		}
188 		if (data[2] & (1U << 23)) {
189 			type_ |= Type.tPOPCNT;
190 		}
191 		if (data[2] & (1U << 25)) {
192 			type_ |= Type.tAESNI;
193 		}
194 		if (data[2] & (1U << 1)) {
195 			type_ |= Type.tPCLMULQDQ;
196 		}
197 		if (data[2] & (1U << 27)) {
198 			type_ |= Type.tOSXSAVE;
199 		}
200 		if (data[2] & (1U << 30)) {
201 			type_ |= Type.tRDRAND;
202 		}
203 		if (data[2] & (1U << 29)) {
204 			type_ |= Type.tF16C;
205 		}
206 
207 		if (data[3] & (1U << 15)) {
208 			type_ |= Type.tCMOV;
209 		}
210 		if (data[3] & (1U << 23)) {
211 			type_ |= Type.tMMX;
212 		}
213 		if (data[3] & (1U << 25)) {
214 			type_ |= Type.tMMX2 | Type.tSSE;
215 		}
216 		if (data[3] & (1U << 26)) {
217 			type_ |= Type.tSSE2;
218 		}
219 
220 		if (type_ & Type.tOSXSAVE) {
221 			// check XFEATURE_ENABLED_MASK[2:1] = '11b'
222 			uint64 bv = getXfeature();
223 			if ((bv & 6) == 6) {
224 				if (data[2] & (1U << 28)) {
225 					type_ |= Type.tAVX;
226 				}
227 				if (data[2] & (1U << 12)) {
228 					type_ |= Type.tFMA;
229 				}
230 			}
231 		}
232 		if (maxNum >= 7) {
233 			data = getCpuidEx(7, 0);
234 			if (type_ & Type.tAVX && data[1] & 0x20) {
235 				type_ |= Type.tAVX2;
236 			}
237 			if (data[1] & (1U << 3)) {
238 				type_ |= Type.tBMI1;
239 			}
240 			if (data[1] & (1U << 8)) {
241 				type_ |= Type.tBMI2;
242 			}
243 			if (data[1] & (1U << 9)) {
244 				type_ |= Type.tENHANCED_REP;
245 			}
246 			if (data[1] & (1U << 18)) {
247 				type_ |= Type.tRDSEED;
248 			}
249 			if (data[1] & (1U << 19)) {
250 				type_ |= Type.tADX;
251 			}
252 			if (data[1] & (1U << 20)) {
253 				type_ |= Type.tSMAP;
254 			}
255 			if (data[1] & (1U << 4)) {
256 				type_ |= Type.tHLE;
257 			}
258 			if (data[1] & (1U << 11)) {
259 				type_ |= Type.tRTM;
260 			}
261 		}
262 		setFamily();
263 	}
264 	void putFamily()
265 	{
266 		writefln("family=%d, model=%X, stepping=%X, extFamily=%d, extModel=%X", family, model, stepping, extFamily, extModel);
267 		writefln("display:family=%X, model=%X", displayFamily, displayModel);
268 	}
269 
270 	bool has(Type type)
271 	{
272 		return ((type & type_) != 0);
273 	}
274 }