]>
Commit | Line | Data |
---|---|---|
2c0262af 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 library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library 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 GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 | */ | |
21 | #ifdef MEM_WRITE | |
22 | ||
943144d9 FB |
23 | #if MEM_WRITE == 0 |
24 | ||
25 | #if DATA_BITS == 8 | |
26 | #define MEM_SUFFIX b_raw | |
27 | #elif DATA_BITS == 16 | |
28 | #define MEM_SUFFIX w_raw | |
29 | #elif DATA_BITS == 32 | |
30 | #define MEM_SUFFIX l_raw | |
14ce26e7 FB |
31 | #elif DATA_BITS == 64 |
32 | #define MEM_SUFFIX q_raw | |
943144d9 FB |
33 | #endif |
34 | ||
35 | #elif MEM_WRITE == 1 | |
36 | ||
37 | #if DATA_BITS == 8 | |
38 | #define MEM_SUFFIX b_kernel | |
39 | #elif DATA_BITS == 16 | |
40 | #define MEM_SUFFIX w_kernel | |
41 | #elif DATA_BITS == 32 | |
42 | #define MEM_SUFFIX l_kernel | |
14ce26e7 FB |
43 | #elif DATA_BITS == 64 |
44 | #define MEM_SUFFIX q_kernel | |
943144d9 FB |
45 | #endif |
46 | ||
47 | #elif MEM_WRITE == 2 | |
48 | ||
2c0262af | 49 | #if DATA_BITS == 8 |
943144d9 | 50 | #define MEM_SUFFIX b_user |
2c0262af | 51 | #elif DATA_BITS == 16 |
943144d9 | 52 | #define MEM_SUFFIX w_user |
2c0262af | 53 | #elif DATA_BITS == 32 |
943144d9 | 54 | #define MEM_SUFFIX l_user |
14ce26e7 FB |
55 | #elif DATA_BITS == 64 |
56 | #define MEM_SUFFIX q_user | |
943144d9 FB |
57 | #endif |
58 | ||
59 | #else | |
60 | ||
61 | #error invalid MEM_WRITE | |
62 | ||
2c0262af FB |
63 | #endif |
64 | ||
65 | #else | |
66 | ||
67 | #define MEM_SUFFIX SUFFIX | |
68 | ||
69 | #endif | |
70 | ||
71 | void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void) | |
72 | { | |
14ce26e7 FB |
73 | int count; |
74 | target_long src; | |
75 | ||
2c0262af FB |
76 | count = T1 & SHIFT_MASK; |
77 | if (count) { | |
78 | src = T0; | |
79 | T0 &= DATA_MASK; | |
80 | T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); | |
81 | #ifdef MEM_WRITE | |
14ce26e7 | 82 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
83 | #else |
84 | /* gcc 3.2 workaround. This is really a bug in gcc. */ | |
85 | asm volatile("" : : "r" (T0)); | |
86 | #endif | |
87 | CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | | |
88 | (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | | |
89 | (T0 & CC_C); | |
90 | CC_OP = CC_OP_EFLAGS; | |
91 | } | |
92 | FORCE_RET(); | |
93 | } | |
94 | ||
95 | void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void) | |
96 | { | |
14ce26e7 FB |
97 | int count; |
98 | target_long src; | |
99 | ||
2c0262af FB |
100 | count = T1 & SHIFT_MASK; |
101 | if (count) { | |
102 | src = T0; | |
103 | T0 &= DATA_MASK; | |
104 | T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); | |
105 | #ifdef MEM_WRITE | |
14ce26e7 | 106 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
107 | #else |
108 | /* gcc 3.2 workaround. This is really a bug in gcc. */ | |
109 | asm volatile("" : : "r" (T0)); | |
110 | #endif | |
111 | CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | | |
112 | (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | | |
113 | ((T0 >> (DATA_BITS - 1)) & CC_C); | |
114 | CC_OP = CC_OP_EFLAGS; | |
115 | } | |
116 | FORCE_RET(); | |
117 | } | |
118 | ||
119 | void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void) | |
120 | { | |
121 | int count; | |
122 | count = T1 & SHIFT_MASK; | |
123 | if (count) { | |
124 | T0 &= DATA_MASK; | |
125 | T0 = (T0 << count) | (T0 >> (DATA_BITS - count)); | |
126 | #ifdef MEM_WRITE | |
14ce26e7 | 127 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
128 | #endif |
129 | } | |
130 | FORCE_RET(); | |
131 | } | |
132 | ||
133 | void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void) | |
134 | { | |
135 | int count; | |
136 | count = T1 & SHIFT_MASK; | |
137 | if (count) { | |
138 | T0 &= DATA_MASK; | |
139 | T0 = (T0 >> count) | (T0 << (DATA_BITS - count)); | |
140 | #ifdef MEM_WRITE | |
14ce26e7 | 141 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
142 | #endif |
143 | } | |
144 | FORCE_RET(); | |
145 | } | |
146 | ||
147 | void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void) | |
148 | { | |
14ce26e7 FB |
149 | int count, eflags; |
150 | target_ulong src; | |
151 | target_long res; | |
2c0262af | 152 | |
14ce26e7 | 153 | count = T1 & SHIFT1_MASK; |
2c0262af FB |
154 | #if DATA_BITS == 16 |
155 | count = rclw_table[count]; | |
156 | #elif DATA_BITS == 8 | |
157 | count = rclb_table[count]; | |
158 | #endif | |
159 | if (count) { | |
160 | eflags = cc_table[CC_OP].compute_all(); | |
161 | T0 &= DATA_MASK; | |
162 | src = T0; | |
31313213 | 163 | res = (T0 << count) | ((target_ulong)(eflags & CC_C) << (count - 1)); |
2c0262af FB |
164 | if (count > 1) |
165 | res |= T0 >> (DATA_BITS + 1 - count); | |
166 | T0 = res; | |
167 | #ifdef MEM_WRITE | |
14ce26e7 | 168 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
169 | #endif |
170 | CC_SRC = (eflags & ~(CC_C | CC_O)) | | |
171 | (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | | |
172 | ((src >> (DATA_BITS - count)) & CC_C); | |
173 | CC_OP = CC_OP_EFLAGS; | |
174 | } | |
175 | FORCE_RET(); | |
176 | } | |
177 | ||
178 | void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void) | |
179 | { | |
14ce26e7 FB |
180 | int count, eflags; |
181 | target_ulong src; | |
182 | target_long res; | |
2c0262af | 183 | |
14ce26e7 | 184 | count = T1 & SHIFT1_MASK; |
2c0262af FB |
185 | #if DATA_BITS == 16 |
186 | count = rclw_table[count]; | |
187 | #elif DATA_BITS == 8 | |
188 | count = rclb_table[count]; | |
189 | #endif | |
190 | if (count) { | |
191 | eflags = cc_table[CC_OP].compute_all(); | |
192 | T0 &= DATA_MASK; | |
193 | src = T0; | |
31313213 | 194 | res = (T0 >> count) | ((target_ulong)(eflags & CC_C) << (DATA_BITS - count)); |
2c0262af FB |
195 | if (count > 1) |
196 | res |= T0 << (DATA_BITS + 1 - count); | |
197 | T0 = res; | |
198 | #ifdef MEM_WRITE | |
14ce26e7 | 199 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
200 | #endif |
201 | CC_SRC = (eflags & ~(CC_C | CC_O)) | | |
202 | (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | | |
203 | ((src >> (count - 1)) & CC_C); | |
204 | CC_OP = CC_OP_EFLAGS; | |
205 | } | |
206 | FORCE_RET(); | |
207 | } | |
208 | ||
209 | void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void) | |
210 | { | |
14ce26e7 FB |
211 | int count; |
212 | target_long src; | |
213 | ||
214 | count = T1 & SHIFT1_MASK; | |
2c0262af FB |
215 | if (count) { |
216 | src = (DATA_TYPE)T0 << (count - 1); | |
217 | T0 = T0 << count; | |
218 | #ifdef MEM_WRITE | |
14ce26e7 | 219 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
220 | #endif |
221 | CC_SRC = src; | |
222 | CC_DST = T0; | |
223 | CC_OP = CC_OP_SHLB + SHIFT; | |
224 | } | |
225 | FORCE_RET(); | |
226 | } | |
227 | ||
228 | void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void) | |
229 | { | |
14ce26e7 FB |
230 | int count; |
231 | target_long src; | |
232 | ||
233 | count = T1 & SHIFT1_MASK; | |
2c0262af FB |
234 | if (count) { |
235 | T0 &= DATA_MASK; | |
236 | src = T0 >> (count - 1); | |
237 | T0 = T0 >> count; | |
238 | #ifdef MEM_WRITE | |
14ce26e7 | 239 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
240 | #endif |
241 | CC_SRC = src; | |
242 | CC_DST = T0; | |
243 | CC_OP = CC_OP_SARB + SHIFT; | |
244 | } | |
245 | FORCE_RET(); | |
246 | } | |
247 | ||
248 | void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void) | |
249 | { | |
14ce26e7 FB |
250 | int count; |
251 | target_long src; | |
252 | ||
253 | count = T1 & SHIFT1_MASK; | |
2c0262af FB |
254 | if (count) { |
255 | src = (DATA_STYPE)T0; | |
256 | T0 = src >> count; | |
257 | src = src >> (count - 1); | |
258 | #ifdef MEM_WRITE | |
14ce26e7 | 259 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
260 | #endif |
261 | CC_SRC = src; | |
262 | CC_DST = T0; | |
263 | CC_OP = CC_OP_SARB + SHIFT; | |
264 | } | |
265 | FORCE_RET(); | |
266 | } | |
267 | ||
268 | #if DATA_BITS == 16 | |
269 | /* XXX: overflow flag might be incorrect in some cases in shldw */ | |
270 | void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) | |
271 | { | |
272 | int count; | |
273 | unsigned int res, tmp; | |
274 | count = PARAM1; | |
275 | T1 &= 0xffff; | |
276 | res = T1 | (T0 << 16); | |
277 | tmp = res >> (32 - count); | |
278 | res <<= count; | |
279 | if (count > 16) | |
280 | res |= T1 << (count - 16); | |
281 | T0 = res >> 16; | |
282 | #ifdef MEM_WRITE | |
14ce26e7 | 283 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
284 | #endif |
285 | CC_SRC = tmp; | |
286 | CC_DST = T0; | |
287 | } | |
288 | ||
289 | void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) | |
290 | { | |
291 | int count; | |
292 | unsigned int res, tmp; | |
293 | count = ECX & 0x1f; | |
294 | if (count) { | |
295 | T1 &= 0xffff; | |
296 | res = T1 | (T0 << 16); | |
297 | tmp = res >> (32 - count); | |
298 | res <<= count; | |
299 | if (count > 16) | |
300 | res |= T1 << (count - 16); | |
301 | T0 = res >> 16; | |
302 | #ifdef MEM_WRITE | |
14ce26e7 | 303 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
304 | #endif |
305 | CC_SRC = tmp; | |
306 | CC_DST = T0; | |
307 | CC_OP = CC_OP_SARB + SHIFT; | |
308 | } | |
309 | FORCE_RET(); | |
310 | } | |
311 | ||
312 | void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) | |
313 | { | |
314 | int count; | |
315 | unsigned int res, tmp; | |
316 | ||
317 | count = PARAM1; | |
318 | res = (T0 & 0xffff) | (T1 << 16); | |
319 | tmp = res >> (count - 1); | |
320 | res >>= count; | |
321 | if (count > 16) | |
322 | res |= T1 << (32 - count); | |
323 | T0 = res; | |
324 | #ifdef MEM_WRITE | |
14ce26e7 | 325 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
326 | #endif |
327 | CC_SRC = tmp; | |
328 | CC_DST = T0; | |
329 | } | |
330 | ||
331 | ||
332 | void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) | |
333 | { | |
334 | int count; | |
335 | unsigned int res, tmp; | |
336 | ||
337 | count = ECX & 0x1f; | |
338 | if (count) { | |
339 | res = (T0 & 0xffff) | (T1 << 16); | |
340 | tmp = res >> (count - 1); | |
341 | res >>= count; | |
342 | if (count > 16) | |
343 | res |= T1 << (32 - count); | |
344 | T0 = res; | |
345 | #ifdef MEM_WRITE | |
14ce26e7 | 346 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
347 | #endif |
348 | CC_SRC = tmp; | |
349 | CC_DST = T0; | |
350 | CC_OP = CC_OP_SARB + SHIFT; | |
351 | } | |
352 | FORCE_RET(); | |
353 | } | |
354 | #endif | |
355 | ||
14ce26e7 | 356 | #if DATA_BITS >= 32 |
2c0262af FB |
357 | void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void) |
358 | { | |
14ce26e7 FB |
359 | int count; |
360 | target_long tmp; | |
361 | ||
2c0262af FB |
362 | count = PARAM1; |
363 | T0 &= DATA_MASK; | |
364 | T1 &= DATA_MASK; | |
365 | tmp = T0 << (count - 1); | |
366 | T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); | |
367 | #ifdef MEM_WRITE | |
14ce26e7 | 368 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
369 | #endif |
370 | CC_SRC = tmp; | |
371 | CC_DST = T0; | |
372 | } | |
373 | ||
374 | void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void) | |
375 | { | |
14ce26e7 FB |
376 | int count; |
377 | target_long tmp; | |
378 | ||
379 | count = ECX & SHIFT1_MASK; | |
2c0262af FB |
380 | if (count) { |
381 | T0 &= DATA_MASK; | |
382 | T1 &= DATA_MASK; | |
383 | tmp = T0 << (count - 1); | |
384 | T0 = (T0 << count) | (T1 >> (DATA_BITS - count)); | |
385 | #ifdef MEM_WRITE | |
14ce26e7 | 386 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
387 | #endif |
388 | CC_SRC = tmp; | |
389 | CC_DST = T0; | |
390 | CC_OP = CC_OP_SHLB + SHIFT; | |
391 | } | |
392 | FORCE_RET(); | |
393 | } | |
394 | ||
395 | void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void) | |
396 | { | |
14ce26e7 FB |
397 | int count; |
398 | target_long tmp; | |
399 | ||
2c0262af FB |
400 | count = PARAM1; |
401 | T0 &= DATA_MASK; | |
402 | T1 &= DATA_MASK; | |
403 | tmp = T0 >> (count - 1); | |
404 | T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); | |
405 | #ifdef MEM_WRITE | |
14ce26e7 | 406 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
407 | #endif |
408 | CC_SRC = tmp; | |
409 | CC_DST = T0; | |
410 | } | |
411 | ||
412 | ||
413 | void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void) | |
414 | { | |
14ce26e7 FB |
415 | int count; |
416 | target_long tmp; | |
417 | ||
418 | count = ECX & SHIFT1_MASK; | |
2c0262af FB |
419 | if (count) { |
420 | T0 &= DATA_MASK; | |
421 | T1 &= DATA_MASK; | |
422 | tmp = T0 >> (count - 1); | |
423 | T0 = (T0 >> count) | (T1 << (DATA_BITS - count)); | |
424 | #ifdef MEM_WRITE | |
14ce26e7 | 425 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
426 | #endif |
427 | CC_SRC = tmp; | |
428 | CC_DST = T0; | |
429 | CC_OP = CC_OP_SARB + SHIFT; | |
430 | } | |
431 | FORCE_RET(); | |
432 | } | |
433 | #endif | |
434 | ||
435 | /* carry add/sub (we only need to set CC_OP differently) */ | |
436 | ||
437 | void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void) | |
438 | { | |
439 | int cf; | |
440 | cf = cc_table[CC_OP].compute_c(); | |
441 | T0 = T0 + T1 + cf; | |
442 | #ifdef MEM_WRITE | |
14ce26e7 | 443 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
444 | #endif |
445 | CC_SRC = T1; | |
446 | CC_DST = T0; | |
14ce26e7 | 447 | CC_OP = CC_OP_ADDB + SHIFT + cf * 4; |
2c0262af FB |
448 | } |
449 | ||
450 | void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void) | |
451 | { | |
452 | int cf; | |
453 | cf = cc_table[CC_OP].compute_c(); | |
454 | T0 = T0 - T1 - cf; | |
455 | #ifdef MEM_WRITE | |
14ce26e7 | 456 | glue(st, MEM_SUFFIX)(A0, T0); |
2c0262af FB |
457 | #endif |
458 | CC_SRC = T1; | |
459 | CC_DST = T0; | |
14ce26e7 | 460 | CC_OP = CC_OP_SUBB + SHIFT + cf * 4; |
2c0262af FB |
461 | } |
462 | ||
463 | void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void) | |
464 | { | |
14ce26e7 | 465 | target_ulong src, dst; |
2c0262af FB |
466 | |
467 | src = T0; | |
468 | dst = EAX - T0; | |
469 | if ((DATA_TYPE)dst == 0) { | |
470 | T0 = T1; | |
1e4fe7ce | 471 | #ifdef MEM_WRITE |
14ce26e7 | 472 | glue(st, MEM_SUFFIX)(A0, T0); |
1e4fe7ce | 473 | #endif |
2c0262af FB |
474 | } else { |
475 | EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK); | |
476 | } | |
2c0262af FB |
477 | CC_SRC = src; |
478 | CC_DST = dst; | |
479 | FORCE_RET(); | |
480 | } | |
481 | ||
482 | #undef MEM_SUFFIX | |
483 | #undef MEM_WRITE |