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