master
c 429 lines 10.7 KB
Raw
1 /*
2 * x86 condition code helpers
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "qemu/osdep.h"
21 #include "cpu.h"
22 #include "exec/helper-proto.h"
23 #include "helper-tcg.h"
24
25 #define SHIFT 0
26 #include "cc_helper_template.h.inc"
27 #undef SHIFT
28
29 #define SHIFT 1
30 #include "cc_helper_template.h.inc"
31 #undef SHIFT
32
33 #define SHIFT 2
34 #include "cc_helper_template.h.inc"
35 #undef SHIFT
36
37 #ifdef TARGET_X86_64
38
39 #define SHIFT 3
40 #include "cc_helper_template.h.inc"
41 #undef SHIFT
42
43 #endif
44
45 static target_ulong compute_all_adcx(target_ulong dst, target_ulong src1,
46 target_ulong src2)
47 {
48 return (src1 & ~CC_C) | (dst * CC_C);
49 }
50
51 static target_ulong compute_all_adox(target_ulong dst, target_ulong src1,
52 target_ulong src2)
53 {
54 return (src1 & ~CC_O) | (src2 * CC_O);
55 }
56
57 static target_ulong compute_all_adcox(target_ulong dst, target_ulong src1,
58 target_ulong src2)
59 {
60 return (src1 & ~(CC_C | CC_O)) | (dst * CC_C) | (src2 * CC_O);
61 }
62
63 target_ulong helper_cc_compute_nz(target_ulong dst, target_ulong src1,
64 int op)
65 {
66 if (CC_OP_HAS_EFLAGS(op)) {
67 return ~src1 & CC_Z;
68 } else {
69 MemOp size = cc_op_size(op);
70 target_ulong mask = MAKE_64BIT_MASK(0, 8 << size);
71
72 return dst & mask;
73 }
74 }
75
76 /* NOTE: we compute the flags like the P4. On olders CPUs, only OF and
77 CF are modified and it is slower to do that. Note as well that we
78 don't truncate SRC1 for computing carry to DATA_TYPE. */
79 static inline uint32_t compute_aco_mul(target_long src1)
80 {
81 uint32_t cf, af, of;
82
83 cf = (src1 != 0);
84 af = 0; /* undefined */
85 of = cf * CC_O;
86 return cf + af + of;
87 }
88
89 target_ulong helper_cc_compute_all(target_ulong dst, target_ulong src1,
90 target_ulong src2, int op)
91 {
92 uint32_t flags = 0;
93 int shift = 0;
94
95 switch (op) {
96 default: /* should never happen */
97 return 0;
98
99 case CC_OP_EFLAGS:
100 return src1;
101 case CC_OP_POPCNT:
102 return dst ? 0 : CC_Z;
103 case CC_OP_SBB_SELF:
104 /* dst is either all zeros (--Z-P-) or all ones (-S-APC) */
105 return (dst & (CC_Z|CC_A|CC_C|CC_S)) ^ (CC_P | CC_Z);
106
107 case CC_OP_ADCX:
108 return compute_all_adcx(dst, src1, src2);
109 case CC_OP_ADOX:
110 return compute_all_adox(dst, src1, src2);
111 case CC_OP_ADCOX:
112 return compute_all_adcox(dst, src1, src2);
113
114 case CC_OP_MULB:
115 flags = compute_aco_mul(src1);
116 goto psz_b;
117 case CC_OP_MULW:
118 flags = compute_aco_mul(src1);
119 goto psz_w;
120 case CC_OP_MULL:
121 flags = compute_aco_mul(src1);
122 goto psz_l;
123
124 case CC_OP_ADDB:
125 flags = compute_aco_addb(dst, src1);
126 goto psz_b;
127 case CC_OP_ADDW:
128 flags = compute_aco_addw(dst, src1);
129 goto psz_w;
130 case CC_OP_ADDL:
131 flags = compute_aco_addl(dst, src1);
132 goto psz_l;
133
134 case CC_OP_ADCB:
135 flags = compute_aco_adcb(dst, src1, src2);
136 goto psz_b;
137 case CC_OP_ADCW:
138 flags = compute_aco_adcw(dst, src1, src2);
139 goto psz_w;
140 case CC_OP_ADCL:
141 flags = compute_aco_adcl(dst, src1, src2);
142 goto psz_l;
143
144 case CC_OP_SUBB:
145 flags = compute_aco_subb(dst, src1);
146 goto psz_b;
147 case CC_OP_SUBW:
148 flags = compute_aco_subw(dst, src1);
149 goto psz_w;
150 case CC_OP_SUBL:
151 flags = compute_aco_subl(dst, src1);
152 goto psz_l;
153
154 case CC_OP_SBBB:
155 flags = compute_aco_sbbb(dst, src1, src2);
156 goto psz_b;
157 case CC_OP_SBBW:
158 flags = compute_aco_sbbw(dst, src1, src2);
159 goto psz_w;
160 case CC_OP_SBBL:
161 flags = compute_aco_sbbl(dst, src1, src2);
162 goto psz_l;
163
164 case CC_OP_LOGICB:
165 flags = 0;
166 goto psz_b;
167 case CC_OP_LOGICW:
168 flags = 0;
169 goto psz_w;
170 case CC_OP_LOGICL:
171 flags = 0;
172 goto psz_l;
173
174 case CC_OP_INCB:
175 flags = compute_aco_incb(dst, src1);
176 goto psz_b;
177 case CC_OP_INCW:
178 flags = compute_aco_incw(dst, src1);
179 goto psz_w;
180 case CC_OP_INCL:
181 flags = compute_aco_incl(dst, src1);
182 goto psz_l;
183
184 case CC_OP_DECB:
185 flags = compute_aco_decb(dst, src1);
186 goto psz_b;
187 case CC_OP_DECW:
188 flags = compute_aco_decw(dst, src1);
189 goto psz_w;
190 case CC_OP_DECL:
191 flags = compute_aco_decl(dst, src1);
192 goto psz_l;
193
194 case CC_OP_SHLB:
195 flags = compute_aco_shlb(dst, src1);
196 goto psz_b;
197 case CC_OP_SHLW:
198 flags = compute_aco_shlw(dst, src1);
199 goto psz_w;
200 case CC_OP_SHLL:
201 flags = compute_aco_shll(dst, src1);
202 goto psz_l;
203
204 case CC_OP_SARB:
205 flags = compute_aco_sarb(dst, src1);
206 goto psz_b;
207 case CC_OP_SARW:
208 flags = compute_aco_sarw(dst, src1);
209 goto psz_w;
210 case CC_OP_SARL:
211 flags = compute_aco_sarl(dst, src1);
212 goto psz_l;
213
214 case CC_OP_BMILGB:
215 flags = compute_aco_bmilgb(dst, src1);
216 goto psz_b;
217 case CC_OP_BMILGW:
218 flags = compute_aco_bmilgw(dst, src1);
219 goto psz_w;
220 case CC_OP_BMILGL:
221 flags = compute_aco_bmilgl(dst, src1);
222 goto psz_l;
223
224 case CC_OP_BLSIB:
225 flags = compute_aco_blsib(dst, src1);
226 goto psz_b;
227 case CC_OP_BLSIW:
228 flags = compute_aco_blsiw(dst, src1);
229 goto psz_w;
230 case CC_OP_BLSIL:
231 flags = compute_aco_blsil(dst, src1);
232 goto psz_l;
233
234 #ifdef TARGET_X86_64
235 case CC_OP_MULQ:
236 flags = compute_aco_mul(src1);
237 goto psz_q;
238 case CC_OP_ADDQ:
239 flags = compute_aco_addq(dst, src1);
240 goto psz_q;
241 case CC_OP_ADCQ:
242 flags = compute_aco_adcq(dst, src1, src2);
243 goto psz_q;
244 case CC_OP_SUBQ:
245 flags = compute_aco_subq(dst, src1);
246 goto psz_q;
247 case CC_OP_SBBQ:
248 flags = compute_aco_sbbq(dst, src1, src2);
249 goto psz_q;
250 case CC_OP_INCQ:
251 flags = compute_aco_incq(dst, src1);
252 goto psz_q;
253 case CC_OP_DECQ:
254 flags = compute_aco_decq(dst, src1);
255 goto psz_q;
256 case CC_OP_LOGICQ:
257 flags = 0;
258 goto psz_q;
259 case CC_OP_SHLQ:
260 flags = compute_aco_shlq(dst, src1);
261 goto psz_q;
262 case CC_OP_SARQ:
263 flags = compute_aco_sarq(dst, src1);
264 goto psz_q;
265 case CC_OP_BMILGQ:
266 flags = compute_aco_bmilgq(dst, src1);
267 goto psz_q;
268 case CC_OP_BLSIQ:
269 flags = compute_aco_blsiq(dst, src1);
270 goto psz_q;
271 #endif
272 }
273
274 psz_b:
275 shift += 8;
276 psz_w:
277 shift += 16;
278 psz_l:
279 #ifdef TARGET_X86_64
280 shift += 32;
281 psz_q:
282 #endif
283
284 flags += compute_pf(dst);
285 dst <<= shift;
286 flags += dst == 0 ? CC_Z : 0;
287 flags += (target_long)dst < 0 ? CC_S : 0;
288 return flags;
289 }
290
291 uint32_t cpu_cc_compute_all(CPUX86State *env)
292 {
293 return helper_cc_compute_all(CC_DST, CC_SRC, CC_SRC2, CC_OP);
294 }
295
296 target_ulong helper_cc_compute_c(target_ulong dst, target_ulong src1,
297 target_ulong src2, int op)
298 {
299 switch (op) {
300 default: /* should never happen */
301 case CC_OP_LOGICB:
302 case CC_OP_LOGICW:
303 case CC_OP_LOGICL:
304 case CC_OP_LOGICQ:
305 case CC_OP_POPCNT:
306 return 0;
307
308 case CC_OP_EFLAGS:
309 case CC_OP_SARB:
310 case CC_OP_SARW:
311 case CC_OP_SARL:
312 case CC_OP_SARQ:
313 case CC_OP_ADOX:
314 return src1 & 1;
315
316 case CC_OP_INCB:
317 case CC_OP_INCW:
318 case CC_OP_INCL:
319 case CC_OP_INCQ:
320 case CC_OP_DECB:
321 case CC_OP_DECW:
322 case CC_OP_DECL:
323 case CC_OP_DECQ:
324 return src1;
325
326 case CC_OP_MULB:
327 case CC_OP_MULW:
328 case CC_OP_MULL:
329 case CC_OP_MULQ:
330 return src1 != 0;
331
332 case CC_OP_SBB_SELF:
333 return dst & 1;
334
335 case CC_OP_ADCX:
336 case CC_OP_ADCOX:
337 return dst;
338
339 case CC_OP_ADDB:
340 return compute_c_addb(dst, src1);
341 case CC_OP_ADDW:
342 return compute_c_addw(dst, src1);
343 case CC_OP_ADDL:
344 return compute_c_addl(dst, src1);
345
346 case CC_OP_ADCB:
347 return compute_c_adcb(dst, src1, src2);
348 case CC_OP_ADCW:
349 return compute_c_adcw(dst, src1, src2);
350 case CC_OP_ADCL:
351 return compute_c_adcl(dst, src1, src2);
352
353 case CC_OP_SUBB:
354 return compute_c_subb(dst, src1);
355 case CC_OP_SUBW:
356 return compute_c_subw(dst, src1);
357 case CC_OP_SUBL:
358 return compute_c_subl(dst, src1);
359
360 case CC_OP_SBBB:
361 return compute_c_sbbb(dst, src1, src2);
362 case CC_OP_SBBW:
363 return compute_c_sbbw(dst, src1, src2);
364 case CC_OP_SBBL:
365 return compute_c_sbbl(dst, src1, src2);
366
367 case CC_OP_SHLB:
368 return compute_c_shlb(dst, src1);
369 case CC_OP_SHLW:
370 return compute_c_shlw(dst, src1);
371 case CC_OP_SHLL:
372 return compute_c_shll(dst, src1);
373
374 case CC_OP_BMILGB:
375 return compute_c_bmilgb(dst, src1);
376 case CC_OP_BMILGW:
377 return compute_c_bmilgw(dst, src1);
378 case CC_OP_BMILGL:
379 return compute_c_bmilgl(dst, src1);
380
381 case CC_OP_BLSIB:
382 return compute_c_blsib(dst, src1);
383 case CC_OP_BLSIW:
384 return compute_c_blsiw(dst, src1);
385 case CC_OP_BLSIL:
386 return compute_c_blsil(dst, src1);
387
388 #ifdef TARGET_X86_64
389 case CC_OP_ADDQ:
390 return compute_c_addq(dst, src1);
391 case CC_OP_ADCQ:
392 return compute_c_adcq(dst, src1, src2);
393 case CC_OP_SUBQ:
394 return compute_c_subq(dst, src1);
395 case CC_OP_SBBQ:
396 return compute_c_sbbq(dst, src1, src2);
397 case CC_OP_SHLQ:
398 return compute_c_shlq(dst, src1);
399 case CC_OP_BMILGQ:
400 return compute_c_bmilgq(dst, src1);
401 case CC_OP_BLSIQ:
402 return compute_c_blsiq(dst, src1);
403 #endif
404 }
405 }
406
407 void helper_write_eflags(CPUX86State *env, target_ulong t0,
408 uint32_t update_mask)
409 {
410 cpu_load_eflags(env, t0, update_mask);
411 }
412
413 target_ulong helper_read_eflags(CPUX86State *env)
414 {
415 uint32_t eflags;
416
417 CC_SRC = eflags = cpu_cc_compute_all(env);
418 CC_OP = CC_OP_EFLAGS;
419
420 eflags |= (env->df & DF_MASK);
421 eflags |= env->eflags & ~(VM_MASK | RF_MASK);
422 return eflags;
423 }
424
425 void helper_clts(CPUX86State *env)
426 {
427 env->cr[0] &= ~CR0_TS_MASK;
428 env->hflags &= ~HF_TS_MASK;
429 }