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