2 * i386 micro operations (included several times to generate
3 * different operand sizes)
5 * Copyright (c) 2003 Fabrice Bellard
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.
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.
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
21 #define DATA_BITS (1 << (3 + SHIFT))
22 #define SHIFT_MASK (DATA_BITS - 1)
23 #define SIGN_MASK (1 << (DATA_BITS - 1))
27 #define DATA_TYPE uint8_t
28 #define DATA_STYPE int8_t
29 #define DATA_MASK 0xff
32 #define DATA_TYPE uint16_t
33 #define DATA_STYPE int16_t
34 #define DATA_MASK 0xffff
37 #define DATA_TYPE uint32_t
38 #define DATA_STYPE int32_t
39 #define DATA_MASK 0xffffffff
41 #error unhandled operand size
44 /* dynamic flags computation */
46 static int glue(compute_all_add
, SUFFIX
)(void)
48 int cf
, pf
, af
, zf
, sf
, of
;
51 src2
= CC_DST
- CC_SRC
;
52 cf
= (DATA_TYPE
)CC_DST
< (DATA_TYPE
)src1
;
53 pf
= parity_table
[(uint8_t)CC_DST
];
54 af
= (CC_DST
^ src1
^ src2
) & 0x10;
55 zf
= ((DATA_TYPE
)CC_DST
== 0) << 6;
56 sf
= lshift(CC_DST
, 8 - DATA_BITS
) & 0x80;
57 of
= lshift((src1
^ src2
^ -1) & (src1
^ CC_DST
), 12 - DATA_BITS
) & CC_O
;
58 return cf
| pf
| af
| zf
| sf
| of
;
61 static int glue(compute_c_add
, SUFFIX
)(void)
65 cf
= (DATA_TYPE
)CC_DST
< (DATA_TYPE
)src1
;
69 static int glue(compute_all_adc
, SUFFIX
)(void)
71 int cf
, pf
, af
, zf
, sf
, of
;
74 src2
= CC_DST
- CC_SRC
- 1;
75 cf
= (DATA_TYPE
)CC_DST
<= (DATA_TYPE
)src1
;
76 pf
= parity_table
[(uint8_t)CC_DST
];
77 af
= (CC_DST
^ src1
^ src2
) & 0x10;
78 zf
= ((DATA_TYPE
)CC_DST
== 0) << 6;
79 sf
= lshift(CC_DST
, 8 - DATA_BITS
) & 0x80;
80 of
= lshift((src1
^ src2
^ -1) & (src1
^ CC_DST
), 12 - DATA_BITS
) & CC_O
;
81 return cf
| pf
| af
| zf
| sf
| of
;
84 static int glue(compute_c_adc
, SUFFIX
)(void)
88 cf
= (DATA_TYPE
)CC_DST
<= (DATA_TYPE
)src1
;
92 static int glue(compute_all_sub
, SUFFIX
)(void)
94 int cf
, pf
, af
, zf
, sf
, of
;
96 src1
= CC_DST
+ CC_SRC
;
98 cf
= (DATA_TYPE
)src1
< (DATA_TYPE
)src2
;
99 pf
= parity_table
[(uint8_t)CC_DST
];
100 af
= (CC_DST
^ src1
^ src2
) & 0x10;
101 zf
= ((DATA_TYPE
)CC_DST
== 0) << 6;
102 sf
= lshift(CC_DST
, 8 - DATA_BITS
) & 0x80;
103 of
= lshift((src1
^ src2
) & (src1
^ CC_DST
), 12 - DATA_BITS
) & CC_O
;
104 return cf
| pf
| af
| zf
| sf
| of
;
107 static int glue(compute_c_sub
, SUFFIX
)(void)
110 src1
= CC_DST
+ CC_SRC
;
112 cf
= (DATA_TYPE
)src1
< (DATA_TYPE
)src2
;
116 static int glue(compute_all_sbb
, SUFFIX
)(void)
118 int cf
, pf
, af
, zf
, sf
, of
;
120 src1
= CC_DST
+ CC_SRC
+ 1;
122 cf
= (DATA_TYPE
)src1
<= (DATA_TYPE
)src2
;
123 pf
= parity_table
[(uint8_t)CC_DST
];
124 af
= (CC_DST
^ src1
^ src2
) & 0x10;
125 zf
= ((DATA_TYPE
)CC_DST
== 0) << 6;
126 sf
= lshift(CC_DST
, 8 - DATA_BITS
) & 0x80;
127 of
= lshift((src1
^ src2
) & (src1
^ CC_DST
), 12 - DATA_BITS
) & CC_O
;
128 return cf
| pf
| af
| zf
| sf
| of
;
131 static int glue(compute_c_sbb
, SUFFIX
)(void)
134 src1
= CC_DST
+ CC_SRC
+ 1;
136 cf
= (DATA_TYPE
)src1
<= (DATA_TYPE
)src2
;
140 static int glue(compute_all_logic
, SUFFIX
)(void)
142 int cf
, pf
, af
, zf
, sf
, of
;
144 pf
= parity_table
[(uint8_t)CC_DST
];
146 zf
= ((DATA_TYPE
)CC_DST
== 0) << 6;
147 sf
= lshift(CC_DST
, 8 - DATA_BITS
) & 0x80;
149 return cf
| pf
| af
| zf
| sf
| of
;
152 static int glue(compute_c_logic
, SUFFIX
)(void)
157 static int glue(compute_all_inc
, SUFFIX
)(void)
159 int cf
, pf
, af
, zf
, sf
, of
;
164 pf
= parity_table
[(uint8_t)CC_DST
];
165 af
= (CC_DST
^ src1
^ src2
) & 0x10;
166 zf
= ((DATA_TYPE
)CC_DST
== 0) << 6;
167 sf
= lshift(CC_DST
, 8 - DATA_BITS
) & 0x80;
168 of
= ((CC_DST
& DATA_MASK
) == SIGN_MASK
) << 11;
169 return cf
| pf
| af
| zf
| sf
| of
;
173 static int glue(compute_c_inc
, SUFFIX
)(void)
179 static int glue(compute_all_dec
, SUFFIX
)(void)
181 int cf
, pf
, af
, zf
, sf
, of
;
186 pf
= parity_table
[(uint8_t)CC_DST
];
187 af
= (CC_DST
^ src1
^ src2
) & 0x10;
188 zf
= ((DATA_TYPE
)CC_DST
== 0) << 6;
189 sf
= lshift(CC_DST
, 8 - DATA_BITS
) & 0x80;
190 of
= ((CC_DST
& DATA_MASK
) == ((uint32_t)SIGN_MASK
- 1)) << 11;
191 return cf
| pf
| af
| zf
| sf
| of
;
194 static int glue(compute_all_shl
, SUFFIX
)(void)
196 int cf
, pf
, af
, zf
, sf
, of
;
197 cf
= (CC_SRC
>> (DATA_BITS
- 1)) & CC_C
;
198 pf
= parity_table
[(uint8_t)CC_DST
];
199 af
= 0; /* undefined */
200 zf
= ((DATA_TYPE
)CC_DST
== 0) << 6;
201 sf
= lshift(CC_DST
, 8 - DATA_BITS
) & 0x80;
202 /* of is defined if shift count == 1 */
203 of
= lshift(CC_SRC
^ CC_DST
, 12 - DATA_BITS
) & CC_O
;
204 return cf
| pf
| af
| zf
| sf
| of
;
207 static int glue(compute_c_shl
, SUFFIX
)(void)
209 return (CC_SRC
>> (DATA_BITS
- 1)) & CC_C
;
213 static int glue(compute_c_sar
, SUFFIX
)(void)
219 static int glue(compute_all_sar
, SUFFIX
)(void)
221 int cf
, pf
, af
, zf
, sf
, of
;
223 pf
= parity_table
[(uint8_t)CC_DST
];
224 af
= 0; /* undefined */
225 zf
= ((DATA_TYPE
)CC_DST
== 0) << 6;
226 sf
= lshift(CC_DST
, 8 - DATA_BITS
) & 0x80;
227 /* of is defined if shift count == 1 */
228 of
= lshift(CC_SRC
^ CC_DST
, 12 - DATA_BITS
) & CC_O
;
229 return cf
| pf
| af
| zf
| sf
| of
;
232 /* various optimized jumps cases */
234 void OPPROTO
glue(op_jb_sub
, SUFFIX
)(void)
237 src1
= CC_DST
+ CC_SRC
;
240 if ((DATA_TYPE
)src1
< (DATA_TYPE
)src2
)
241 JUMP_TB(PARAM1
, 0, PARAM2
);
243 JUMP_TB(PARAM1
, 1, PARAM3
);
247 void OPPROTO
glue(op_jz_sub
, SUFFIX
)(void)
249 if ((DATA_TYPE
)CC_DST
== 0)
250 JUMP_TB(PARAM1
, 0, PARAM2
);
252 JUMP_TB(PARAM1
, 1, PARAM3
);
256 void OPPROTO
glue(op_jbe_sub
, SUFFIX
)(void)
259 src1
= CC_DST
+ CC_SRC
;
262 if ((DATA_TYPE
)src1
<= (DATA_TYPE
)src2
)
263 JUMP_TB(PARAM1
, 0, PARAM2
);
265 JUMP_TB(PARAM1
, 1, PARAM3
);
269 void OPPROTO
glue(op_js_sub
, SUFFIX
)(void)
271 if (CC_DST
& SIGN_MASK
)
272 JUMP_TB(PARAM1
, 0, PARAM2
);
274 JUMP_TB(PARAM1
, 1, PARAM3
);
278 void OPPROTO
glue(op_jl_sub
, SUFFIX
)(void)
281 src1
= CC_DST
+ CC_SRC
;
284 if ((DATA_STYPE
)src1
< (DATA_STYPE
)src2
)
285 JUMP_TB(PARAM1
, 0, PARAM2
);
287 JUMP_TB(PARAM1
, 1, PARAM3
);
291 void OPPROTO
glue(op_jle_sub
, SUFFIX
)(void)
294 src1
= CC_DST
+ CC_SRC
;
297 if ((DATA_STYPE
)src1
<= (DATA_STYPE
)src2
)
298 JUMP_TB(PARAM1
, 0, PARAM2
);
300 JUMP_TB(PARAM1
, 1, PARAM3
);
308 void OPPROTO
glue(op_loopnz
, SUFFIX
)(void)
312 eflags
= cc_table
[CC_OP
].compute_all();
313 tmp
= (ECX
- 1) & DATA_MASK
;
314 ECX
= (ECX
& ~DATA_MASK
) | tmp
;
315 if (tmp
!= 0 && !(eflags
& CC_Z
))
322 void OPPROTO
glue(op_loopz
, SUFFIX
)(void)
326 eflags
= cc_table
[CC_OP
].compute_all();
327 tmp
= (ECX
- 1) & DATA_MASK
;
328 ECX
= (ECX
& ~DATA_MASK
) | tmp
;
329 if (tmp
!= 0 && (eflags
& CC_Z
))
336 void OPPROTO
glue(op_loop
, SUFFIX
)(void)
339 tmp
= (ECX
- 1) & DATA_MASK
;
340 ECX
= (ECX
& ~DATA_MASK
) | tmp
;
348 void OPPROTO
glue(op_jecxz
, SUFFIX
)(void)
350 if ((DATA_TYPE
)ECX
== 0)
359 /* various optimized set cases */
361 void OPPROTO
glue(op_setb_T0_sub
, SUFFIX
)(void)
364 src1
= CC_DST
+ CC_SRC
;
367 T0
= ((DATA_TYPE
)src1
< (DATA_TYPE
)src2
);
370 void OPPROTO
glue(op_setz_T0_sub
, SUFFIX
)(void)
372 T0
= ((DATA_TYPE
)CC_DST
== 0);
375 void OPPROTO
glue(op_setbe_T0_sub
, SUFFIX
)(void)
378 src1
= CC_DST
+ CC_SRC
;
381 T0
= ((DATA_TYPE
)src1
<= (DATA_TYPE
)src2
);
384 void OPPROTO
glue(op_sets_T0_sub
, SUFFIX
)(void)
386 T0
= lshift(CC_DST
, -(DATA_BITS
- 1)) & 1;
389 void OPPROTO
glue(op_setl_T0_sub
, SUFFIX
)(void)
392 src1
= CC_DST
+ CC_SRC
;
395 T0
= ((DATA_STYPE
)src1
< (DATA_STYPE
)src2
);
398 void OPPROTO
glue(op_setle_T0_sub
, SUFFIX
)(void)
401 src1
= CC_DST
+ CC_SRC
;
404 T0
= ((DATA_STYPE
)src1
<= (DATA_STYPE
)src2
);
409 void OPPROTO
glue(glue(op_shl
, SUFFIX
), _T0_T1
)(void)
417 void OPPROTO
glue(glue(op_shr
, SUFFIX
), _T0_T1
)(void)
426 void OPPROTO
glue(glue(op_sar
, SUFFIX
), _T0_T1
)(void)
430 src
= (DATA_STYPE
)T0
;
436 #include "ops_template_mem.h"
439 #include "ops_template_mem.h"
444 void OPPROTO
glue(glue(op_bt
, SUFFIX
), _T0_T1_cc
)(void)
447 count
= T1
& SHIFT_MASK
;
448 CC_SRC
= T0
>> count
;
451 void OPPROTO
glue(glue(op_bts
, SUFFIX
), _T0_T1_cc
)(void)
454 count
= T1
& SHIFT_MASK
;
459 void OPPROTO
glue(glue(op_btr
, SUFFIX
), _T0_T1_cc
)(void)
462 count
= T1
& SHIFT_MASK
;
467 void OPPROTO
glue(glue(op_btc
, SUFFIX
), _T0_T1_cc
)(void)
470 count
= T1
& SHIFT_MASK
;
475 void OPPROTO
glue(glue(op_bsf
, SUFFIX
), _T0_cc
)(void)
478 res
= T0
& DATA_MASK
;
481 while ((res
& 1) == 0) {
486 CC_DST
= 1; /* ZF = 1 */
488 CC_DST
= 0; /* ZF = 1 */
493 void OPPROTO
glue(glue(op_bsr
, SUFFIX
), _T0_cc
)(void)
496 res
= T0
& DATA_MASK
;
498 count
= DATA_BITS
- 1;
499 while ((res
& SIGN_MASK
) == 0) {
504 CC_DST
= 1; /* ZF = 1 */
506 CC_DST
= 0; /* ZF = 1 */
514 void OPPROTO
op_update_bt_cc(void)
520 /* string operations */
521 /* XXX: maybe use lower level instructions to ease 16 bit / segment handling */
523 #define STRING_SUFFIX _fast
524 #define SI_ADDR (void *)ESI
525 #define DI_ADDR (void *)EDI
526 #define INC_SI() ESI += inc
527 #define INC_DI() EDI += inc
529 #define DEC_CX() ECX--
530 #include "op_string.h"
532 #define STRING_SUFFIX _a32
533 #define SI_ADDR (uint8_t *)A0 + ESI
534 #define DI_ADDR env->segs[R_ES].base + EDI
535 #define INC_SI() ESI += inc
536 #define INC_DI() EDI += inc
538 #define DEC_CX() ECX--
539 #include "op_string.h"
541 #define STRING_SUFFIX _a16
542 #define SI_ADDR (uint8_t *)A0 + (ESI & 0xffff)
543 #define DI_ADDR env->segs[R_ES].base + (EDI & 0xffff)
544 #define INC_SI() ESI = (ESI & ~0xffff) | ((ESI + inc) & 0xffff)
545 #define INC_DI() EDI = (EDI & ~0xffff) | ((EDI + inc) & 0xffff)
546 #define CX (ECX & 0xffff)
547 #define DEC_CX() ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff)
548 #include "op_string.h"
552 void OPPROTO
glue(glue(op_out
, SUFFIX
), _T0_T1
)(void)
554 glue(cpu_x86_out
, SUFFIX
)(env
, T0
& 0xffff, T1
& DATA_MASK
);
557 void OPPROTO
glue(glue(op_in
, SUFFIX
), _T0_T1
)(void)
559 T1
= glue(cpu_x86_in
, SUFFIX
)(env
, T0
& 0xffff);