]>
Commit | Line | Data |
---|---|---|
66fb9763 FB |
1 | /* |
2 | * i386 micro operations (included several times to generate | |
3 | * different operand sizes) | |
4 | * | |
5 | * Copyright (c) 2003 Fabrice Bellard | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | */ | |
367e86e8 FB |
21 | |
22 | #define DATA_BITS (1 << (3 + SHIFT)) | |
23 | #define SHIFT_MASK (DATA_BITS - 1) | |
24 | #define SIGN_MASK (1 << (DATA_BITS - 1)) | |
25 | ||
26 | #if DATA_BITS == 8 | |
27 | #define SUFFIX b | |
28 | #define DATA_TYPE uint8_t | |
29 | #define DATA_STYPE int8_t | |
30 | #define DATA_MASK 0xff | |
31 | #elif DATA_BITS == 16 | |
32 | #define SUFFIX w | |
33 | #define DATA_TYPE uint16_t | |
34 | #define DATA_STYPE int16_t | |
35 | #define DATA_MASK 0xffff | |
36 | #elif DATA_BITS == 32 | |
37 | #define SUFFIX l | |
38 | #define DATA_TYPE uint32_t | |
39 | #define DATA_STYPE int32_t | |
40 | #define DATA_MASK 0xffffffff | |
41 | #else | |
42 | #error unhandled operand size | |
43 | #endif | |
44 | ||
45 | /* dynamic flags computation */ | |
46 | ||
47 | static int glue(compute_all_add, SUFFIX)(void) | |
48 | { | |
49 | int cf, pf, af, zf, sf, of; | |
50 | int src1, src2; | |
51 | src1 = CC_SRC; | |
52 | src2 = CC_DST - CC_SRC; | |
53 | cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; | |
54 | pf = parity_table[(uint8_t)CC_DST]; | |
55 | af = (CC_DST ^ src1 ^ src2) & 0x10; | |
4b74fe1f | 56 | zf = ((DATA_TYPE)CC_DST == 0) << 6; |
367e86e8 FB |
57 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; |
58 | of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; | |
59 | return cf | pf | af | zf | sf | of; | |
60 | } | |
61 | ||
62 | static int glue(compute_c_add, SUFFIX)(void) | |
63 | { | |
64 | int src1, cf; | |
65 | src1 = CC_SRC; | |
66 | cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1; | |
67 | return cf; | |
68 | } | |
69 | ||
4b74fe1f FB |
70 | static int glue(compute_all_adc, SUFFIX)(void) |
71 | { | |
72 | int cf, pf, af, zf, sf, of; | |
73 | int src1, src2; | |
74 | src1 = CC_SRC; | |
75 | src2 = CC_DST - CC_SRC - 1; | |
76 | cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; | |
77 | pf = parity_table[(uint8_t)CC_DST]; | |
78 | af = (CC_DST ^ src1 ^ src2) & 0x10; | |
79 | zf = ((DATA_TYPE)CC_DST == 0) << 6; | |
80 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; | |
81 | of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; | |
82 | return cf | pf | af | zf | sf | of; | |
83 | } | |
84 | ||
85 | static int glue(compute_c_adc, SUFFIX)(void) | |
86 | { | |
87 | int src1, cf; | |
88 | src1 = CC_SRC; | |
89 | cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1; | |
90 | return cf; | |
91 | } | |
92 | ||
367e86e8 FB |
93 | static int glue(compute_all_sub, SUFFIX)(void) |
94 | { | |
95 | int cf, pf, af, zf, sf, of; | |
96 | int src1, src2; | |
97 | src1 = CC_SRC; | |
98 | src2 = CC_SRC - CC_DST; | |
99 | cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; | |
100 | pf = parity_table[(uint8_t)CC_DST]; | |
101 | af = (CC_DST ^ src1 ^ src2) & 0x10; | |
4b74fe1f | 102 | zf = ((DATA_TYPE)CC_DST == 0) << 6; |
367e86e8 | 103 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; |
4b74fe1f | 104 | of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; |
367e86e8 FB |
105 | return cf | pf | af | zf | sf | of; |
106 | } | |
107 | ||
108 | static int glue(compute_c_sub, SUFFIX)(void) | |
109 | { | |
110 | int src1, src2, cf; | |
111 | src1 = CC_SRC; | |
112 | src2 = CC_SRC - CC_DST; | |
4b74fe1f FB |
113 | cf = (DATA_TYPE)src1 < (DATA_TYPE)src2; |
114 | return cf; | |
115 | } | |
116 | ||
117 | static int glue(compute_all_sbb, SUFFIX)(void) | |
118 | { | |
119 | int cf, pf, af, zf, sf, of; | |
120 | int src1, src2; | |
121 | src1 = CC_SRC; | |
122 | src2 = CC_SRC - CC_DST - 1; | |
123 | cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; | |
124 | pf = parity_table[(uint8_t)CC_DST]; | |
125 | af = (CC_DST ^ src1 ^ src2) & 0x10; | |
126 | zf = ((DATA_TYPE)CC_DST == 0) << 6; | |
127 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; | |
128 | of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O; | |
129 | return cf | pf | af | zf | sf | of; | |
130 | } | |
131 | ||
132 | static int glue(compute_c_sbb, SUFFIX)(void) | |
133 | { | |
134 | int src1, src2, cf; | |
135 | src1 = CC_SRC; | |
136 | src2 = CC_SRC - CC_DST - 1; | |
137 | cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2; | |
367e86e8 FB |
138 | return cf; |
139 | } | |
140 | ||
141 | static int glue(compute_all_logic, SUFFIX)(void) | |
142 | { | |
143 | int cf, pf, af, zf, sf, of; | |
144 | cf = 0; | |
145 | pf = parity_table[(uint8_t)CC_DST]; | |
146 | af = 0; | |
4b74fe1f | 147 | zf = ((DATA_TYPE)CC_DST == 0) << 6; |
367e86e8 FB |
148 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; |
149 | of = 0; | |
150 | return cf | pf | af | zf | sf | of; | |
151 | } | |
152 | ||
153 | static int glue(compute_c_logic, SUFFIX)(void) | |
154 | { | |
155 | return 0; | |
156 | } | |
157 | ||
158 | static int glue(compute_all_inc, SUFFIX)(void) | |
159 | { | |
160 | int cf, pf, af, zf, sf, of; | |
161 | int src1, src2; | |
162 | src1 = CC_DST - 1; | |
163 | src2 = 1; | |
164 | cf = CC_SRC; | |
165 | pf = parity_table[(uint8_t)CC_DST]; | |
166 | af = (CC_DST ^ src1 ^ src2) & 0x10; | |
4b74fe1f | 167 | zf = ((DATA_TYPE)CC_DST == 0) << 6; |
367e86e8 | 168 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; |
4b74fe1f | 169 | of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11; |
367e86e8 FB |
170 | return cf | pf | af | zf | sf | of; |
171 | } | |
172 | ||
4b74fe1f | 173 | #if DATA_BITS == 32 |
367e86e8 FB |
174 | static int glue(compute_c_inc, SUFFIX)(void) |
175 | { | |
176 | return CC_SRC; | |
177 | } | |
4b74fe1f | 178 | #endif |
367e86e8 FB |
179 | |
180 | static int glue(compute_all_dec, SUFFIX)(void) | |
181 | { | |
182 | int cf, pf, af, zf, sf, of; | |
183 | int src1, src2; | |
184 | src1 = CC_DST + 1; | |
185 | src2 = 1; | |
186 | cf = CC_SRC; | |
187 | pf = parity_table[(uint8_t)CC_DST]; | |
188 | af = (CC_DST ^ src1 ^ src2) & 0x10; | |
4b74fe1f | 189 | zf = ((DATA_TYPE)CC_DST == 0) << 6; |
367e86e8 | 190 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; |
4b74fe1f | 191 | of = ((CC_DST & DATA_MASK) == ((uint32_t)SIGN_MASK - 1)) << 11; |
367e86e8 FB |
192 | return cf | pf | af | zf | sf | of; |
193 | } | |
194 | ||
195 | static int glue(compute_all_shl, SUFFIX)(void) | |
196 | { | |
197 | int cf, pf, af, zf, sf, of; | |
d57c4e01 | 198 | cf = (CC_SRC >> (DATA_BITS - 1)) & CC_C; |
367e86e8 FB |
199 | pf = parity_table[(uint8_t)CC_DST]; |
200 | af = 0; /* undefined */ | |
4b74fe1f | 201 | zf = ((DATA_TYPE)CC_DST == 0) << 6; |
367e86e8 | 202 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; |
d57c4e01 FB |
203 | /* of is defined if shift count == 1 */ |
204 | of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; | |
367e86e8 FB |
205 | return cf | pf | af | zf | sf | of; |
206 | } | |
207 | ||
4b74fe1f | 208 | #if DATA_BITS == 32 |
367e86e8 FB |
209 | static int glue(compute_c_shl, SUFFIX)(void) |
210 | { | |
211 | return CC_SRC & 1; | |
212 | } | |
4b74fe1f FB |
213 | #endif |
214 | ||
215 | static int glue(compute_all_sar, SUFFIX)(void) | |
216 | { | |
217 | int cf, pf, af, zf, sf, of; | |
218 | cf = CC_SRC & 1; | |
219 | pf = parity_table[(uint8_t)CC_DST]; | |
220 | af = 0; /* undefined */ | |
221 | zf = ((DATA_TYPE)CC_DST == 0) << 6; | |
222 | sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80; | |
d57c4e01 FB |
223 | /* of is defined if shift count == 1 */ |
224 | of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; | |
4b74fe1f FB |
225 | return cf | pf | af | zf | sf | of; |
226 | } | |
367e86e8 FB |
227 | |
228 | /* various optimized jumps cases */ | |
229 | ||
230 | void OPPROTO glue(op_jb_sub, SUFFIX)(void) | |
231 | { | |
232 | int src1, src2; | |
233 | src1 = CC_SRC; | |
234 | src2 = CC_SRC - CC_DST; | |
235 | ||
236 | if ((DATA_TYPE)src1 < (DATA_TYPE)src2) | |
dab2ed99 | 237 | EIP = PARAM1; |
367e86e8 | 238 | else |
dab2ed99 | 239 | EIP = PARAM2; |
367e86e8 FB |
240 | FORCE_RET(); |
241 | } | |
242 | ||
243 | void OPPROTO glue(op_jz_sub, SUFFIX)(void) | |
244 | { | |
4b74fe1f | 245 | if ((DATA_TYPE)CC_DST == 0) |
dab2ed99 | 246 | EIP = PARAM1; |
367e86e8 | 247 | else |
dab2ed99 | 248 | EIP = PARAM2; |
367e86e8 FB |
249 | FORCE_RET(); |
250 | } | |
251 | ||
252 | void OPPROTO glue(op_jbe_sub, SUFFIX)(void) | |
253 | { | |
254 | int src1, src2; | |
255 | src1 = CC_SRC; | |
256 | src2 = CC_SRC - CC_DST; | |
257 | ||
258 | if ((DATA_TYPE)src1 <= (DATA_TYPE)src2) | |
dab2ed99 | 259 | EIP = PARAM1; |
367e86e8 | 260 | else |
dab2ed99 | 261 | EIP = PARAM2; |
367e86e8 FB |
262 | FORCE_RET(); |
263 | } | |
264 | ||
265 | void OPPROTO glue(op_js_sub, SUFFIX)(void) | |
266 | { | |
267 | if (CC_DST & SIGN_MASK) | |
dab2ed99 | 268 | EIP = PARAM1; |
367e86e8 | 269 | else |
dab2ed99 | 270 | EIP = PARAM2; |
367e86e8 FB |
271 | FORCE_RET(); |
272 | } | |
273 | ||
274 | void OPPROTO glue(op_jl_sub, SUFFIX)(void) | |
275 | { | |
276 | int src1, src2; | |
277 | src1 = CC_SRC; | |
278 | src2 = CC_SRC - CC_DST; | |
279 | ||
280 | if ((DATA_STYPE)src1 < (DATA_STYPE)src2) | |
dab2ed99 | 281 | EIP = PARAM1; |
367e86e8 | 282 | else |
dab2ed99 | 283 | EIP = PARAM2; |
367e86e8 FB |
284 | FORCE_RET(); |
285 | } | |
286 | ||
287 | void OPPROTO glue(op_jle_sub, SUFFIX)(void) | |
288 | { | |
289 | int src1, src2; | |
290 | src1 = CC_SRC; | |
291 | src2 = CC_SRC - CC_DST; | |
292 | ||
293 | if ((DATA_STYPE)src1 <= (DATA_STYPE)src2) | |
dab2ed99 | 294 | EIP = PARAM1; |
367e86e8 | 295 | else |
dab2ed99 | 296 | EIP = PARAM2; |
367e86e8 FB |
297 | FORCE_RET(); |
298 | } | |
299 | ||
1a9353d2 FB |
300 | /* oldies */ |
301 | ||
302 | #if DATA_BITS >= 16 | |
303 | ||
304 | void OPPROTO glue(op_loopnz, SUFFIX)(void) | |
305 | { | |
306 | unsigned int tmp; | |
307 | int eflags; | |
308 | eflags = cc_table[CC_OP].compute_all(); | |
309 | tmp = (ECX - 1) & DATA_MASK; | |
310 | ECX = (ECX & ~DATA_MASK) | tmp; | |
311 | if (tmp != 0 && !(eflags & CC_Z)) | |
dab2ed99 | 312 | EIP = PARAM1; |
1a9353d2 | 313 | else |
dab2ed99 | 314 | EIP = PARAM2; |
1a9353d2 FB |
315 | FORCE_RET(); |
316 | } | |
317 | ||
318 | void OPPROTO glue(op_loopz, SUFFIX)(void) | |
319 | { | |
320 | unsigned int tmp; | |
321 | int eflags; | |
322 | eflags = cc_table[CC_OP].compute_all(); | |
323 | tmp = (ECX - 1) & DATA_MASK; | |
324 | ECX = (ECX & ~DATA_MASK) | tmp; | |
325 | if (tmp != 0 && (eflags & CC_Z)) | |
dab2ed99 | 326 | EIP = PARAM1; |
1a9353d2 | 327 | else |
dab2ed99 | 328 | EIP = PARAM2; |
1a9353d2 FB |
329 | FORCE_RET(); |
330 | } | |
331 | ||
332 | void OPPROTO glue(op_loop, SUFFIX)(void) | |
333 | { | |
334 | unsigned int tmp; | |
335 | tmp = (ECX - 1) & DATA_MASK; | |
336 | ECX = (ECX & ~DATA_MASK) | tmp; | |
337 | if (tmp != 0) | |
dab2ed99 | 338 | EIP = PARAM1; |
1a9353d2 | 339 | else |
dab2ed99 | 340 | EIP = PARAM2; |
1a9353d2 FB |
341 | FORCE_RET(); |
342 | } | |
343 | ||
344 | void OPPROTO glue(op_jecxz, SUFFIX)(void) | |
345 | { | |
346 | if ((DATA_TYPE)ECX == 0) | |
dab2ed99 | 347 | EIP = PARAM1; |
1a9353d2 | 348 | else |
dab2ed99 | 349 | EIP = PARAM2; |
1a9353d2 FB |
350 | FORCE_RET(); |
351 | } | |
352 | ||
353 | #endif | |
354 | ||
367e86e8 FB |
355 | /* various optimized set cases */ |
356 | ||
357 | void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void) | |
358 | { | |
359 | int src1, src2; | |
360 | src1 = CC_SRC; | |
361 | src2 = CC_SRC - CC_DST; | |
362 | ||
363 | T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2); | |
364 | } | |
365 | ||
366 | void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void) | |
367 | { | |
4b74fe1f | 368 | T0 = ((DATA_TYPE)CC_DST == 0); |
367e86e8 FB |
369 | } |
370 | ||
371 | void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void) | |
372 | { | |
373 | int src1, src2; | |
374 | src1 = CC_SRC; | |
375 | src2 = CC_SRC - CC_DST; | |
376 | ||
377 | T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2); | |
378 | } | |
379 | ||
380 | void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void) | |
381 | { | |
382 | T0 = lshift(CC_DST, -(DATA_BITS - 1)) & 1; | |
383 | } | |
384 | ||
385 | void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void) | |
386 | { | |
387 | int src1, src2; | |
388 | src1 = CC_SRC; | |
389 | src2 = CC_SRC - CC_DST; | |
390 | ||
391 | T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2); | |
392 | } | |
393 | ||
394 | void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void) | |
395 | { | |
396 | int src1, src2; | |
397 | src1 = CC_SRC; | |
398 | src2 = CC_SRC - CC_DST; | |
399 | ||
400 | T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2); | |
401 | } | |
402 | ||
403 | /* shifts */ | |
404 | ||
405 | void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void) | |
406 | { | |
407 | int count, src; | |
408 | count = T1 & SHIFT_MASK; | |
409 | if (count) { | |
410 | CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C); | |
411 | src = T0; | |
412 | T0 &= DATA_MASK; | |
413 | T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); | |
414 | CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | | |
415 | (T0 & CC_C); | |
416 | CC_OP = CC_OP_EFLAGS; | |
417 | } | |
4b74fe1f | 418 | FORCE_RET(); |
367e86e8 FB |
419 | } |
420 | ||
dc99065b FB |
421 | void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1)(void) |
422 | { | |
423 | int count; | |
424 | count = T1 & SHIFT_MASK; | |
425 | if (count) { | |
426 | T0 &= DATA_MASK; | |
427 | T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); | |
428 | } | |
429 | FORCE_RET(); | |
430 | } | |
431 | ||
367e86e8 FB |
432 | void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void) |
433 | { | |
434 | int count, src; | |
435 | count = T1 & SHIFT_MASK; | |
436 | if (count) { | |
437 | CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C); | |
438 | src = T0; | |
439 | T0 &= DATA_MASK; | |
440 | T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); | |
441 | CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | | |
442 | ((T0 >> (DATA_BITS - 1)) & CC_C); | |
443 | CC_OP = CC_OP_EFLAGS; | |
444 | } | |
4b74fe1f | 445 | FORCE_RET(); |
367e86e8 FB |
446 | } |
447 | ||
dc99065b FB |
448 | void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1)(void) |
449 | { | |
450 | int count; | |
451 | count = T1 & SHIFT_MASK; | |
452 | if (count) { | |
453 | T0 &= DATA_MASK; | |
454 | T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); | |
455 | } | |
456 | FORCE_RET(); | |
457 | } | |
458 | ||
367e86e8 FB |
459 | void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void) |
460 | { | |
461 | int count, res, eflags; | |
462 | unsigned int src; | |
463 | ||
464 | count = T1 & 0x1f; | |
465 | #if DATA_BITS == 16 | |
466 | count = rclw_table[count]; | |
467 | #elif DATA_BITS == 8 | |
468 | count = rclb_table[count]; | |
469 | #endif | |
470 | if (count) { | |
471 | eflags = cc_table[CC_OP].compute_all(); | |
4b74fe1f | 472 | T0 &= DATA_MASK; |
367e86e8 FB |
473 | src = T0; |
474 | res = (T0 << count) | ((eflags & CC_C) << (count - 1)); | |
475 | if (count > 1) | |
476 | res |= T0 >> (DATA_BITS + 1 - count); | |
477 | T0 = res; | |
478 | CC_SRC = (eflags & ~(CC_C | CC_O)) | | |
479 | (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | | |
480 | ((src >> (DATA_BITS - count)) & CC_C); | |
481 | CC_OP = CC_OP_EFLAGS; | |
482 | } | |
4b74fe1f | 483 | FORCE_RET(); |
367e86e8 FB |
484 | } |
485 | ||
486 | void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void) | |
487 | { | |
488 | int count, res, eflags; | |
489 | unsigned int src; | |
490 | ||
491 | count = T1 & 0x1f; | |
492 | #if DATA_BITS == 16 | |
493 | count = rclw_table[count]; | |
494 | #elif DATA_BITS == 8 | |
495 | count = rclb_table[count]; | |
496 | #endif | |
497 | if (count) { | |
498 | eflags = cc_table[CC_OP].compute_all(); | |
4b74fe1f | 499 | T0 &= DATA_MASK; |
367e86e8 FB |
500 | src = T0; |
501 | res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count)); | |
502 | if (count > 1) | |
503 | res |= T0 << (DATA_BITS + 1 - count); | |
504 | T0 = res; | |
505 | CC_SRC = (eflags & ~(CC_C | CC_O)) | | |
506 | (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | | |
507 | ((src >> (count - 1)) & CC_C); | |
508 | CC_OP = CC_OP_EFLAGS; | |
509 | } | |
4b74fe1f | 510 | FORCE_RET(); |
367e86e8 FB |
511 | } |
512 | ||
513 | void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void) | |
514 | { | |
515 | int count; | |
516 | count = T1 & 0x1f; | |
d57c4e01 FB |
517 | if (count) { |
518 | CC_SRC = (DATA_TYPE)T0 << (count - 1); | |
367e86e8 FB |
519 | T0 = T0 << count; |
520 | CC_DST = T0; | |
521 | CC_OP = CC_OP_SHLB + SHIFT; | |
522 | } | |
4b74fe1f | 523 | FORCE_RET(); |
367e86e8 FB |
524 | } |
525 | ||
dc99065b FB |
526 | void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void) |
527 | { | |
528 | int count; | |
529 | count = T1 & 0x1f; | |
530 | T0 = T0 << count; | |
531 | FORCE_RET(); | |
532 | } | |
533 | ||
367e86e8 FB |
534 | void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void) |
535 | { | |
536 | int count; | |
537 | count = T1 & 0x1f; | |
538 | if (count) { | |
539 | T0 &= DATA_MASK; | |
540 | CC_SRC = T0 >> (count - 1); | |
541 | T0 = T0 >> count; | |
542 | CC_DST = T0; | |
d57c4e01 | 543 | CC_OP = CC_OP_SARB + SHIFT; |
367e86e8 | 544 | } |
4b74fe1f | 545 | FORCE_RET(); |
367e86e8 FB |
546 | } |
547 | ||
dc99065b FB |
548 | void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void) |
549 | { | |
550 | int count; | |
551 | count = T1 & 0x1f; | |
552 | T0 &= DATA_MASK; | |
553 | T0 = T0 >> count; | |
554 | FORCE_RET(); | |
555 | } | |
556 | ||
367e86e8 FB |
557 | void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void) |
558 | { | |
559 | int count, src; | |
560 | count = T1 & 0x1f; | |
561 | if (count) { | |
562 | src = (DATA_STYPE)T0; | |
d57c4e01 | 563 | CC_SRC = src >> (count - 1); |
367e86e8 FB |
564 | T0 = src >> count; |
565 | CC_DST = T0; | |
4b74fe1f | 566 | CC_OP = CC_OP_SARB + SHIFT; |
367e86e8 | 567 | } |
4b74fe1f | 568 | FORCE_RET(); |
367e86e8 FB |
569 | } |
570 | ||
dc99065b FB |
571 | void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void) |
572 | { | |
573 | int count, src; | |
574 | count = T1 & 0x1f; | |
575 | src = (DATA_STYPE)T0; | |
576 | T0 = src >> count; | |
577 | FORCE_RET(); | |
578 | } | |
579 | ||
d57c4e01 FB |
580 | #if DATA_BITS == 16 |
581 | /* XXX: overflow flag might be incorrect in some cases in shldw */ | |
582 | void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void) | |
583 | { | |
584 | int count; | |
585 | unsigned int res; | |
586 | count = PARAM1; | |
587 | T1 &= 0xffff; | |
588 | res = T1 | (T0 << 16); | |
589 | CC_SRC = res >> (32 - count); | |
590 | res <<= count; | |
591 | if (count > 16) | |
592 | res |= T1 << (count - 16); | |
593 | T0 = res >> 16; | |
594 | CC_DST = T0; | |
595 | } | |
596 | ||
597 | void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void) | |
598 | { | |
599 | int count; | |
600 | unsigned int res; | |
601 | count = ECX & 0x1f; | |
602 | if (count) { | |
603 | T1 &= 0xffff; | |
604 | res = T1 | (T0 << 16); | |
605 | CC_SRC = res >> (32 - count); | |
606 | res <<= count; | |
607 | if (count > 16) | |
608 | res |= T1 << (count - 16); | |
609 | T0 = res >> 16; | |
610 | CC_DST = T0; | |
611 | CC_OP = CC_OP_SARB + SHIFT; | |
612 | } | |
613 | } | |
614 | ||
615 | void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void) | |
616 | { | |
617 | int count; | |
618 | unsigned int res; | |
619 | ||
620 | count = PARAM1; | |
621 | res = (T0 & 0xffff) | (T1 << 16); | |
622 | CC_SRC = res >> (count - 1); | |
623 | res >>= count; | |
624 | if (count > 16) | |
625 | res |= T1 << (32 - count); | |
626 | T0 = res; | |
627 | CC_DST = T0; | |
628 | } | |
629 | ||
630 | ||
631 | void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void) | |
632 | { | |
633 | int count; | |
634 | unsigned int res; | |
635 | ||
636 | count = ECX & 0x1f; | |
637 | if (count) { | |
638 | res = (T0 & 0xffff) | (T1 << 16); | |
639 | CC_SRC = res >> (count - 1); | |
640 | res >>= count; | |
641 | if (count > 16) | |
642 | res |= T1 << (32 - count); | |
643 | T0 = res; | |
644 | CC_DST = T0; | |
645 | CC_OP = CC_OP_SARB + SHIFT; | |
646 | } | |
647 | } | |
648 | #endif | |
649 | ||
650 | #if DATA_BITS == 32 | |
651 | void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void) | |
652 | { | |
653 | int count; | |
654 | count = PARAM1; | |
655 | T0 &= DATA_MASK; | |
656 | T1 &= DATA_MASK; | |
657 | CC_SRC = T0 << (count - 1); | |
658 | T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); | |
659 | CC_DST = T0; | |
660 | } | |
661 | ||
662 | void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void) | |
663 | { | |
664 | int count; | |
665 | count = ECX & 0x1f; | |
666 | if (count) { | |
667 | T0 &= DATA_MASK; | |
668 | T1 &= DATA_MASK; | |
669 | CC_SRC = T0 << (count - 1); | |
670 | T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); | |
671 | CC_DST = T0; | |
672 | CC_OP = CC_OP_SHLB + SHIFT; | |
673 | } | |
674 | } | |
675 | ||
676 | void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void) | |
677 | { | |
678 | int count; | |
679 | count = PARAM1; | |
680 | T0 &= DATA_MASK; | |
681 | T1 &= DATA_MASK; | |
682 | CC_SRC = T0 >> (count - 1); | |
683 | T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); | |
684 | CC_DST = T0; | |
685 | } | |
686 | ||
687 | ||
688 | void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void) | |
689 | { | |
690 | int count; | |
691 | count = ECX & 0x1f; | |
692 | if (count) { | |
693 | T0 &= DATA_MASK; | |
694 | T1 &= DATA_MASK; | |
695 | CC_SRC = T0 >> (count - 1); | |
696 | T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); | |
697 | CC_DST = T0; | |
698 | CC_OP = CC_OP_SARB + SHIFT; | |
699 | } | |
700 | } | |
701 | #endif | |
702 | ||
4b74fe1f FB |
703 | /* carry add/sub (we only need to set CC_OP differently) */ |
704 | ||
705 | void OPPROTO glue(glue(op_adc, SUFFIX), _T0_T1_cc)(void) | |
706 | { | |
707 | int cf; | |
708 | cf = cc_table[CC_OP].compute_c(); | |
709 | CC_SRC = T0; | |
710 | T0 = T0 + T1 + cf; | |
711 | CC_DST = T0; | |
712 | CC_OP = CC_OP_ADDB + SHIFT + cf * 3; | |
713 | } | |
714 | ||
715 | void OPPROTO glue(glue(op_sbb, SUFFIX), _T0_T1_cc)(void) | |
716 | { | |
717 | int cf; | |
718 | cf = cc_table[CC_OP].compute_c(); | |
719 | CC_SRC = T0; | |
720 | T0 = T0 - T1 - cf; | |
721 | CC_DST = T0; | |
722 | CC_OP = CC_OP_SUBB + SHIFT + cf * 3; | |
723 | } | |
724 | ||
1a9353d2 FB |
725 | void OPPROTO glue(glue(op_cmpxchg, SUFFIX), _T0_T1_EAX_cc)(void) |
726 | { | |
727 | CC_SRC = EAX; | |
728 | CC_DST = EAX - T0; | |
729 | if ((DATA_TYPE)CC_DST == 0) { | |
730 | T0 = T1; | |
731 | } else { | |
732 | EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK); | |
733 | } | |
734 | FORCE_RET(); | |
735 | } | |
736 | ||
4b74fe1f FB |
737 | /* bit operations */ |
738 | #if DATA_BITS >= 16 | |
739 | ||
740 | void OPPROTO glue(glue(op_bt, SUFFIX), _T0_T1_cc)(void) | |
741 | { | |
742 | int count; | |
743 | count = T1 & SHIFT_MASK; | |
744 | CC_SRC = T0 >> count; | |
745 | } | |
746 | ||
747 | void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void) | |
748 | { | |
749 | int count; | |
750 | count = T1 & SHIFT_MASK; | |
751 | CC_SRC = T0 >> count; | |
752 | T0 |= (1 << count); | |
753 | } | |
754 | ||
755 | void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void) | |
756 | { | |
757 | int count; | |
758 | count = T1 & SHIFT_MASK; | |
759 | CC_SRC = T0 >> count; | |
760 | T0 &= ~(1 << count); | |
761 | } | |
762 | ||
763 | void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void) | |
764 | { | |
765 | int count; | |
766 | count = T1 & SHIFT_MASK; | |
767 | CC_SRC = T0 >> count; | |
768 | T0 ^= (1 << count); | |
769 | } | |
770 | ||
77f8dd5a FB |
771 | void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void) |
772 | { | |
773 | int res, count; | |
774 | res = T0 & DATA_MASK; | |
775 | if (res != 0) { | |
776 | count = 0; | |
777 | while ((res & 1) == 0) { | |
778 | count++; | |
779 | res >>= 1; | |
780 | } | |
781 | T0 = count; | |
782 | CC_DST = 1; /* ZF = 1 */ | |
783 | } else { | |
784 | CC_DST = 0; /* ZF = 1 */ | |
785 | } | |
786 | FORCE_RET(); | |
787 | } | |
788 | ||
789 | void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void) | |
790 | { | |
791 | int res, count; | |
792 | res = T0 & DATA_MASK; | |
793 | if (res != 0) { | |
794 | count = DATA_BITS - 1; | |
795 | while ((res & SIGN_MASK) == 0) { | |
796 | count--; | |
797 | res <<= 1; | |
798 | } | |
799 | T0 = count; | |
800 | CC_DST = 1; /* ZF = 1 */ | |
801 | } else { | |
802 | CC_DST = 0; /* ZF = 1 */ | |
803 | } | |
804 | FORCE_RET(); | |
805 | } | |
806 | ||
4b74fe1f FB |
807 | #endif |
808 | ||
367e86e8 FB |
809 | /* string operations */ |
810 | /* XXX: maybe use lower level instructions to ease exception handling */ | |
811 | ||
812 | void OPPROTO glue(op_movs, SUFFIX)(void) | |
813 | { | |
814 | int v; | |
815 | v = glue(ldu, SUFFIX)((void *)ESI); | |
816 | glue(st, SUFFIX)((void *)EDI, v); | |
817 | ESI += (DF << SHIFT); | |
818 | EDI += (DF << SHIFT); | |
819 | } | |
820 | ||
821 | void OPPROTO glue(op_rep_movs, SUFFIX)(void) | |
822 | { | |
823 | int v, inc; | |
824 | inc = (DF << SHIFT); | |
825 | while (ECX != 0) { | |
826 | v = glue(ldu, SUFFIX)((void *)ESI); | |
827 | glue(st, SUFFIX)((void *)EDI, v); | |
828 | ESI += inc; | |
829 | EDI += inc; | |
830 | ECX--; | |
831 | } | |
04369ff2 | 832 | FORCE_RET(); |
367e86e8 FB |
833 | } |
834 | ||
835 | void OPPROTO glue(op_stos, SUFFIX)(void) | |
836 | { | |
837 | glue(st, SUFFIX)((void *)EDI, EAX); | |
838 | EDI += (DF << SHIFT); | |
839 | } | |
840 | ||
841 | void OPPROTO glue(op_rep_stos, SUFFIX)(void) | |
842 | { | |
843 | int inc; | |
844 | inc = (DF << SHIFT); | |
845 | while (ECX != 0) { | |
846 | glue(st, SUFFIX)((void *)EDI, EAX); | |
847 | EDI += inc; | |
848 | ECX--; | |
849 | } | |
04369ff2 | 850 | FORCE_RET(); |
367e86e8 FB |
851 | } |
852 | ||
853 | void OPPROTO glue(op_lods, SUFFIX)(void) | |
854 | { | |
855 | int v; | |
856 | v = glue(ldu, SUFFIX)((void *)ESI); | |
857 | #if SHIFT == 0 | |
858 | EAX = (EAX & ~0xff) | v; | |
859 | #elif SHIFT == 1 | |
860 | EAX = (EAX & ~0xffff) | v; | |
861 | #else | |
862 | EAX = v; | |
863 | #endif | |
864 | ESI += (DF << SHIFT); | |
865 | } | |
866 | ||
867 | /* don't know if it is used */ | |
868 | void OPPROTO glue(op_rep_lods, SUFFIX)(void) | |
869 | { | |
870 | int v, inc; | |
871 | inc = (DF << SHIFT); | |
872 | while (ECX != 0) { | |
873 | v = glue(ldu, SUFFIX)((void *)ESI); | |
874 | #if SHIFT == 0 | |
875 | EAX = (EAX & ~0xff) | v; | |
876 | #elif SHIFT == 1 | |
877 | EAX = (EAX & ~0xffff) | v; | |
878 | #else | |
879 | EAX = v; | |
880 | #endif | |
881 | ESI += inc; | |
882 | ECX--; | |
883 | } | |
04369ff2 | 884 | FORCE_RET(); |
367e86e8 FB |
885 | } |
886 | ||
887 | void OPPROTO glue(op_scas, SUFFIX)(void) | |
888 | { | |
889 | int v; | |
890 | ||
4b74fe1f FB |
891 | v = glue(ldu, SUFFIX)((void *)EDI); |
892 | EDI += (DF << SHIFT); | |
367e86e8 FB |
893 | CC_SRC = EAX; |
894 | CC_DST = EAX - v; | |
895 | } | |
896 | ||
897 | void OPPROTO glue(op_repz_scas, SUFFIX)(void) | |
898 | { | |
899 | int v1, v2, inc; | |
900 | ||
901 | if (ECX != 0) { | |
902 | /* NOTE: the flags are not modified if ECX == 0 */ | |
4b74fe1f | 903 | v1 = EAX & DATA_MASK; |
367e86e8 FB |
904 | inc = (DF << SHIFT); |
905 | do { | |
4b74fe1f FB |
906 | v2 = glue(ldu, SUFFIX)((void *)EDI); |
907 | EDI += inc; | |
908 | ECX--; | |
367e86e8 FB |
909 | if (v1 != v2) |
910 | break; | |
367e86e8 FB |
911 | } while (ECX != 0); |
912 | CC_SRC = v1; | |
913 | CC_DST = v1 - v2; | |
914 | CC_OP = CC_OP_SUBB + SHIFT; | |
915 | } | |
04369ff2 | 916 | FORCE_RET(); |
367e86e8 FB |
917 | } |
918 | ||
919 | void OPPROTO glue(op_repnz_scas, SUFFIX)(void) | |
920 | { | |
921 | int v1, v2, inc; | |
922 | ||
923 | if (ECX != 0) { | |
924 | /* NOTE: the flags are not modified if ECX == 0 */ | |
4b74fe1f | 925 | v1 = EAX & DATA_MASK; |
367e86e8 FB |
926 | inc = (DF << SHIFT); |
927 | do { | |
4b74fe1f FB |
928 | v2 = glue(ldu, SUFFIX)((void *)EDI); |
929 | EDI += inc; | |
930 | ECX--; | |
367e86e8 FB |
931 | if (v1 == v2) |
932 | break; | |
367e86e8 FB |
933 | } while (ECX != 0); |
934 | CC_SRC = v1; | |
935 | CC_DST = v1 - v2; | |
936 | CC_OP = CC_OP_SUBB + SHIFT; | |
937 | } | |
04369ff2 | 938 | FORCE_RET(); |
367e86e8 FB |
939 | } |
940 | ||
941 | void OPPROTO glue(op_cmps, SUFFIX)(void) | |
942 | { | |
943 | int v1, v2; | |
944 | v1 = glue(ldu, SUFFIX)((void *)ESI); | |
945 | v2 = glue(ldu, SUFFIX)((void *)EDI); | |
946 | ESI += (DF << SHIFT); | |
947 | EDI += (DF << SHIFT); | |
948 | CC_SRC = v1; | |
949 | CC_DST = v1 - v2; | |
950 | } | |
951 | ||
952 | void OPPROTO glue(op_repz_cmps, SUFFIX)(void) | |
953 | { | |
954 | int v1, v2, inc; | |
955 | if (ECX != 0) { | |
956 | inc = (DF << SHIFT); | |
957 | do { | |
958 | v1 = glue(ldu, SUFFIX)((void *)ESI); | |
959 | v2 = glue(ldu, SUFFIX)((void *)EDI); | |
367e86e8 FB |
960 | ESI += inc; |
961 | EDI += inc; | |
962 | ECX--; | |
4b74fe1f FB |
963 | if (v1 != v2) |
964 | break; | |
367e86e8 FB |
965 | } while (ECX != 0); |
966 | CC_SRC = v1; | |
967 | CC_DST = v1 - v2; | |
968 | CC_OP = CC_OP_SUBB + SHIFT; | |
969 | } | |
04369ff2 | 970 | FORCE_RET(); |
367e86e8 FB |
971 | } |
972 | ||
973 | void OPPROTO glue(op_repnz_cmps, SUFFIX)(void) | |
974 | { | |
975 | int v1, v2, inc; | |
976 | if (ECX != 0) { | |
977 | inc = (DF << SHIFT); | |
978 | do { | |
979 | v1 = glue(ldu, SUFFIX)((void *)ESI); | |
980 | v2 = glue(ldu, SUFFIX)((void *)EDI); | |
367e86e8 FB |
981 | ESI += inc; |
982 | EDI += inc; | |
983 | ECX--; | |
4b74fe1f FB |
984 | if (v1 == v2) |
985 | break; | |
367e86e8 FB |
986 | } while (ECX != 0); |
987 | CC_SRC = v1; | |
988 | CC_DST = v1 - v2; | |
989 | CC_OP = CC_OP_SUBB + SHIFT; | |
990 | } | |
04369ff2 | 991 | FORCE_RET(); |
367e86e8 FB |
992 | } |
993 | ||
ba1c6e37 FB |
994 | /* port I/O */ |
995 | ||
367e86e8 FB |
996 | void OPPROTO glue(op_outs, SUFFIX)(void) |
997 | { | |
998 | int v, dx; | |
999 | dx = EDX & 0xffff; | |
1000 | v = glue(ldu, SUFFIX)((void *)ESI); | |
ba1c6e37 | 1001 | glue(cpu_x86_out, SUFFIX)(dx, v); |
367e86e8 FB |
1002 | ESI += (DF << SHIFT); |
1003 | } | |
1004 | ||
1005 | void OPPROTO glue(op_rep_outs, SUFFIX)(void) | |
1006 | { | |
1007 | int v, dx, inc; | |
1008 | inc = (DF << SHIFT); | |
1009 | dx = EDX & 0xffff; | |
1010 | while (ECX != 0) { | |
1011 | v = glue(ldu, SUFFIX)((void *)ESI); | |
ba1c6e37 | 1012 | glue(cpu_x86_out, SUFFIX)(dx, v); |
367e86e8 FB |
1013 | ESI += inc; |
1014 | ECX--; | |
1015 | } | |
04369ff2 | 1016 | FORCE_RET(); |
367e86e8 FB |
1017 | } |
1018 | ||
1019 | void OPPROTO glue(op_ins, SUFFIX)(void) | |
1020 | { | |
1021 | int v, dx; | |
1022 | dx = EDX & 0xffff; | |
ba1c6e37 | 1023 | v = glue(cpu_x86_in, SUFFIX)(dx); |
367e86e8 FB |
1024 | glue(st, SUFFIX)((void *)EDI, v); |
1025 | EDI += (DF << SHIFT); | |
1026 | } | |
1027 | ||
1028 | void OPPROTO glue(op_rep_ins, SUFFIX)(void) | |
1029 | { | |
1030 | int v, dx, inc; | |
1031 | inc = (DF << SHIFT); | |
1032 | dx = EDX & 0xffff; | |
1033 | while (ECX != 0) { | |
ba1c6e37 | 1034 | v = glue(cpu_x86_in, SUFFIX)(dx); |
367e86e8 FB |
1035 | glue(st, SUFFIX)((void *)EDI, v); |
1036 | EDI += (DF << SHIFT); | |
1037 | ECX--; | |
1038 | } | |
04369ff2 | 1039 | FORCE_RET(); |
367e86e8 FB |
1040 | } |
1041 | ||
ba1c6e37 FB |
1042 | void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void) |
1043 | { | |
1044 | glue(cpu_x86_out, SUFFIX)(T0 & 0xffff, T1 & DATA_MASK); | |
1045 | } | |
1046 | ||
1047 | void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void) | |
1048 | { | |
1049 | T1 = glue(cpu_x86_in, SUFFIX)(T0 & 0xffff); | |
1050 | } | |
1051 | ||
367e86e8 FB |
1052 | #undef DATA_BITS |
1053 | #undef SHIFT_MASK | |
1054 | #undef SIGN_MASK | |
1055 | #undef DATA_TYPE | |
1056 | #undef DATA_STYPE | |
1057 | #undef DATA_MASK | |
1058 | #undef SUFFIX |