blob: eeaa2035448754520e364104c9bf0d935c919b6a [file] [log] [blame]
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001/****************************************************************************
2*
3* Realmode X86 Emulator Library
4*
5* Copyright (C) 1991-2004 SciTech Software, Inc.
6* Copyright (C) David Mosberger-Tang
7* Copyright (C) 1999 Egbert Eich
8*
9* ========================================================================
10*
11* Permission to use, copy, modify, distribute, and sell this software and
12* its documentation for any purpose is hereby granted without fee,
13* provided that the above copyright notice appear in all copies and that
14* both that copyright notice and this permission notice appear in
15* supporting documentation, and that the name of the authors not be used
16* in advertising or publicity pertaining to distribution of the software
17* without specific, written prior permission. The authors makes no
18* representations about the suitability of this software for any purpose.
19* It is provided "as is" without express or implied warranty.
20*
21* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
22* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
23* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
24* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
25* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
26* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
27* PERFORMANCE OF THIS SOFTWARE.
28*
29* ========================================================================
30*
31* Language: ANSI C
32* Environment: Any
33* Developer: Kendall Bennett
34*
35* Description: This file includes subroutines to implement the decoding
36* and emulation of all the x86 processor instructions.
37*
38* There are approximately 250 subroutines in here, which correspond
39* to the 256 byte-"opcodes" found on the 8086. The table which
40* dispatches this is found in the files optab.[ch].
41*
Martin Roth63373ed2013-07-08 16:24:19 -060042* Each opcode proc has a comment preceding it which gives it's table
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000043* address. Several opcodes are missing (undefined) in the table.
44*
45* Each proc includes information for decoding (DECODE_PRINTF and
46* DECODE_PRINTF2), debugging (TRACE_REGS, SINGLE_STEP), and misc
47* functions (START_OF_INSTR, END_OF_INSTR).
48*
49* Many of the procedures are *VERY* similar in coding. This has
50* allowed for a very large amount of code to be generated in a fairly
51* short amount of time (i.e. cut, paste, and modify). The result is
52* that much of the code below could have been folded into subroutines
53* for a large reduction in size of this file. The downside would be
54* that there would be a penalty in execution speed. The file could
55* also have been *MUCH* larger by inlining certain functions which
56* were called. This could have resulted even faster execution. The
57* prime directive I used to decide whether to inline the code or to
58* modularize it, was basically: 1) no unnecessary subroutine calls,
59* 2) no routines more than about 200 lines in size, and 3) modularize
60* any code that I might not get right the first time. The fetch_*
Jonathan Neuschäfer45e6c822018-12-11 17:53:07 +010061* subroutines fall into the latter category. The decode_* fall
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000062* into the second category. The coding of the "switch(mod){ .... }"
63* in many of the subroutines below falls into the first category.
64* Especially, the coding of {add,and,or,sub,...}_{byte,word}
65* subroutines are an especially glaring case of the third guideline.
66* Since so much of the code is cloned from other modules (compare
67* opcode #00 to opcode #01), making the basic operations subroutine
68* calls is especially important; otherwise mistakes in coding an
69* "add" would represent a nightmare in maintenance.
70*
71****************************************************************************/
72
73#include "x86emui.h"
74
75/*----------------------------- Implementation ----------------------------*/
76
77/* constant arrays to do several instructions in just one function */
78
Myles Watson8e9234f2010-02-19 19:08:11 +000079#ifdef DEBUG
Uwe Hermann01ce6012010-03-05 10:03:50 +000080static const char *x86emu_GenOpName[8] = {
Stefan Reinauer38cd29e2009-08-11 21:28:25 +000081 "ADD", "OR", "ADC", "SBB", "AND", "SUB", "XOR", "CMP"};
82#endif
83
84/* used by several opcodes */
85static u8 (*genop_byte_operation[])(u8 d, u8 s) =
86{
87 add_byte, /* 00 */
88 or_byte, /* 01 */
89 adc_byte, /* 02 */
90 sbb_byte, /* 03 */
91 and_byte, /* 04 */
92 sub_byte, /* 05 */
93 xor_byte, /* 06 */
94 cmp_byte, /* 07 */
95};
96
97static u16 (*genop_word_operation[])(u16 d, u16 s) =
98{
99 add_word, /*00 */
100 or_word, /*01 */
101 adc_word, /*02 */
102 sbb_word, /*03 */
103 and_word, /*04 */
104 sub_word, /*05 */
105 xor_word, /*06 */
106 cmp_word, /*07 */
107};
108
109static u32 (*genop_long_operation[])(u32 d, u32 s) =
110{
111 add_long, /*00 */
112 or_long, /*01 */
113 adc_long, /*02 */
114 sbb_long, /*03 */
115 and_long, /*04 */
116 sub_long, /*05 */
117 xor_long, /*06 */
118 cmp_long, /*07 */
119};
120
121/* used by opcodes 80, c0, d0, and d2. */
122static u8(*opcD0_byte_operation[])(u8 d, u8 s) =
123{
124 rol_byte,
125 ror_byte,
126 rcl_byte,
127 rcr_byte,
128 shl_byte,
129 shr_byte,
130 shl_byte, /* sal_byte === shl_byte by definition */
131 sar_byte,
132};
133
134/* used by opcodes c1, d1, and d3. */
135static u16(*opcD1_word_operation[])(u16 s, u8 d) =
136{
137 rol_word,
138 ror_word,
139 rcl_word,
140 rcr_word,
141 shl_word,
142 shr_word,
143 shl_word, /* sal_byte === shl_byte by definition */
144 sar_word,
145};
146
147/* used by opcodes c1, d1, and d3. */
148static u32 (*opcD1_long_operation[])(u32 s, u8 d) =
149{
150 rol_long,
151 ror_long,
152 rcl_long,
153 rcr_long,
154 shl_long,
155 shr_long,
156 shl_long, /* sal_byte === shl_byte by definition */
157 sar_long,
158};
159
Myles Watson8e9234f2010-02-19 19:08:11 +0000160#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000161
Uwe Hermann01ce6012010-03-05 10:03:50 +0000162static const char *opF6_names[8] =
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000163 { "TEST\t", "", "NOT\t", "NEG\t", "MUL\t", "IMUL\t", "DIV\t", "IDIV\t" };
164
165#endif
166
167/****************************************************************************
168PARAMETERS:
169op1 - Instruction op code
170
171REMARKS:
172Handles illegal opcodes.
173****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000174static void x86emuOp_illegal_op(
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000175 u8 op1)
176{
177 START_OF_INSTR();
178 if (M.x86.R_SP != 0) {
179 DECODE_PRINTF("ILLEGAL X86 OPCODE\n");
180 TRACE_REGS();
Uwe Hermann01ce6012010-03-05 10:03:50 +0000181 DB( printf("%04x:%04x: %02X ILLEGAL X86 OPCODE!\n",
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000182 M.x86.R_CS, M.x86.R_IP-1,op1));
183 HALT_SYS();
184 }
185 else {
186 /* If we get here, it means the stack pointer is back to zero
187 * so we are just returning from an emulator service call
188 * so therte is no need to display an error message. We trap
189 * the emulator with an 0xF1 opcode to finish the service
190 * call.
191 */
192 X86EMU_halt_sys();
193 }
194 END_OF_INSTR();
195}
196
197/****************************************************************************
198REMARKS:
199Handles opcodes 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38
200****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000201static void x86emuOp_genop_byte_RM_R(u8 op1)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000202{
203 int mod, rl, rh;
204 uint destoffset;
205 u8 *destreg, *srcreg;
206 u8 destval;
207
208 op1 = (op1 >> 3) & 0x7;
209
210 START_OF_INSTR();
211 DECODE_PRINTF(x86emu_GenOpName[op1]);
212 DECODE_PRINTF("\t");
213 FETCH_DECODE_MODRM(mod, rh, rl);
Elyes HAOUASf772f9c2016-08-21 18:28:17 +0200214 if (mod<3)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000215 { destoffset = decode_rmXX_address(mod,rl);
216 DECODE_PRINTF(",");
217 destval = fetch_data_byte(destoffset);
218 srcreg = DECODE_RM_BYTE_REGISTER(rh);
219 DECODE_PRINTF("\n");
220 TRACE_AND_STEP();
221 destval = genop_byte_operation[op1](destval, *srcreg);
222 if (op1 != 7)
223 store_data_byte(destoffset, destval);
224 }
225 else
226 { /* register to register */
227 destreg = DECODE_RM_BYTE_REGISTER(rl);
228 DECODE_PRINTF(",");
229 srcreg = DECODE_RM_BYTE_REGISTER(rh);
230 DECODE_PRINTF("\n");
231 TRACE_AND_STEP();
232 *destreg = genop_byte_operation[op1](*destreg, *srcreg);
233 }
234 DECODE_CLEAR_SEGOVR();
235 END_OF_INSTR();
236}
237
238/****************************************************************************
239REMARKS:
240Handles opcodes 0x01, 0x09, 0x11, 0x19, 0x21, 0x29, 0x31, 0x39
241****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000242static void x86emuOp_genop_word_RM_R(u8 op1)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000243{
244 int mod, rl, rh;
245 uint destoffset;
246
247 op1 = (op1 >> 3) & 0x7;
248
249 START_OF_INSTR();
250 DECODE_PRINTF(x86emu_GenOpName[op1]);
251 DECODE_PRINTF("\t");
252 FETCH_DECODE_MODRM(mod, rh, rl);
253
Elyes HAOUASf772f9c2016-08-21 18:28:17 +0200254 if (mod<3) {
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000255 destoffset = decode_rmXX_address(mod,rl);
256 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
257 u32 destval;
258 u32 *srcreg;
259
260 DECODE_PRINTF(",");
261 destval = fetch_data_long(destoffset);
262 srcreg = DECODE_RM_LONG_REGISTER(rh);
263 DECODE_PRINTF("\n");
264 TRACE_AND_STEP();
265 destval = genop_long_operation[op1](destval, *srcreg);
266 if (op1 != 7)
267 store_data_long(destoffset, destval);
268 } else {
269 u16 destval;
270 u16 *srcreg;
271
272 DECODE_PRINTF(",");
273 destval = fetch_data_word(destoffset);
274 srcreg = DECODE_RM_WORD_REGISTER(rh);
275 DECODE_PRINTF("\n");
276 TRACE_AND_STEP();
277 destval = genop_word_operation[op1](destval, *srcreg);
278 if (op1 != 7)
279 store_data_word(destoffset, destval);
280 }
281 } else { /* register to register */
282 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
283 u32 *destreg, *srcreg;
284
285 destreg = DECODE_RM_LONG_REGISTER(rl);
286 DECODE_PRINTF(",");
287 srcreg = DECODE_RM_LONG_REGISTER(rh);
288 DECODE_PRINTF("\n");
289 TRACE_AND_STEP();
290 *destreg = genop_long_operation[op1](*destreg, *srcreg);
291 } else {
292 u16 *destreg, *srcreg;
293
294 destreg = DECODE_RM_WORD_REGISTER(rl);
295 DECODE_PRINTF(",");
296 srcreg = DECODE_RM_WORD_REGISTER(rh);
297 DECODE_PRINTF("\n");
298 TRACE_AND_STEP();
299 *destreg = genop_word_operation[op1](*destreg, *srcreg);
300 }
301 }
302 DECODE_CLEAR_SEGOVR();
303 END_OF_INSTR();
304}
305
306/****************************************************************************
307REMARKS:
308Handles opcodes 0x02, 0x0a, 0x12, 0x1a, 0x22, 0x2a, 0x32, 0x3a
309****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000310static void x86emuOp_genop_byte_R_RM(u8 op1)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000311{
312 int mod, rl, rh;
313 u8 *destreg, *srcreg;
314 uint srcoffset;
315 u8 srcval;
316
317 op1 = (op1 >> 3) & 0x7;
318
319 START_OF_INSTR();
320 DECODE_PRINTF(x86emu_GenOpName[op1]);
321 DECODE_PRINTF("\t");
322 FETCH_DECODE_MODRM(mod, rh, rl);
323 if (mod < 3) {
324 destreg = DECODE_RM_BYTE_REGISTER(rh);
325 DECODE_PRINTF(",");
326 srcoffset = decode_rmXX_address(mod,rl);
327 srcval = fetch_data_byte(srcoffset);
328 } else { /* register to register */
329 destreg = DECODE_RM_BYTE_REGISTER(rh);
330 DECODE_PRINTF(",");
331 srcreg = DECODE_RM_BYTE_REGISTER(rl);
332 srcval = *srcreg;
333 }
334 DECODE_PRINTF("\n");
335 TRACE_AND_STEP();
336 *destreg = genop_byte_operation[op1](*destreg, srcval);
337
338 DECODE_CLEAR_SEGOVR();
339 END_OF_INSTR();
340}
341
342/****************************************************************************
343REMARKS:
344Handles opcodes 0x03, 0x0b, 0x13, 0x1b, 0x23, 0x2b, 0x33, 0x3b
345****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000346static void x86emuOp_genop_word_R_RM(u8 op1)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000347{
348 int mod, rl, rh;
349 uint srcoffset;
350 u32 *destreg32, srcval;
351 u16 *destreg;
352
353 op1 = (op1 >> 3) & 0x7;
354
355 START_OF_INSTR();
356 DECODE_PRINTF(x86emu_GenOpName[op1]);
357 DECODE_PRINTF("\t");
358 FETCH_DECODE_MODRM(mod, rh, rl);
359 if (mod < 3) {
360 srcoffset = decode_rmXX_address(mod,rl);
361 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
362 destreg32 = DECODE_RM_LONG_REGISTER(rh);
363 DECODE_PRINTF(",");
364 srcval = fetch_data_long(srcoffset);
365 DECODE_PRINTF("\n");
366 TRACE_AND_STEP();
367 *destreg32 = genop_long_operation[op1](*destreg32, srcval);
368 } else {
369 destreg = DECODE_RM_WORD_REGISTER(rh);
370 DECODE_PRINTF(",");
371 srcval = fetch_data_word(srcoffset);
372 DECODE_PRINTF("\n");
373 TRACE_AND_STEP();
374 *destreg = genop_word_operation[op1](*destreg, srcval);
375 }
376 } else { /* register to register */
377 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
378 u32 *srcreg;
379 destreg32 = DECODE_RM_LONG_REGISTER(rh);
380 DECODE_PRINTF(",");
381 srcreg = DECODE_RM_LONG_REGISTER(rl);
382 DECODE_PRINTF("\n");
383 TRACE_AND_STEP();
384 *destreg32 = genop_long_operation[op1](*destreg32, *srcreg);
385 } else {
386 u16 *srcreg;
387 destreg = DECODE_RM_WORD_REGISTER(rh);
388 DECODE_PRINTF(",");
389 srcreg = DECODE_RM_WORD_REGISTER(rl);
390 DECODE_PRINTF("\n");
391 TRACE_AND_STEP();
392 *destreg = genop_word_operation[op1](*destreg, *srcreg);
393 }
394 }
395 DECODE_CLEAR_SEGOVR();
396 END_OF_INSTR();
397}
398
399/****************************************************************************
400REMARKS:
401Handles opcodes 0x04, 0x0c, 0x14, 0x1c, 0x24, 0x2c, 0x34, 0x3c
402****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000403static void x86emuOp_genop_byte_AL_IMM(u8 op1)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000404{
405 u8 srcval;
406
407 op1 = (op1 >> 3) & 0x7;
408
409 START_OF_INSTR();
410 DECODE_PRINTF(x86emu_GenOpName[op1]);
411 DECODE_PRINTF("\tAL,");
412 srcval = fetch_byte_imm();
413 DECODE_PRINTF2("%x\n", srcval);
414 TRACE_AND_STEP();
415 M.x86.R_AL = genop_byte_operation[op1](M.x86.R_AL, srcval);
416 DECODE_CLEAR_SEGOVR();
417 END_OF_INSTR();
418}
419
420/****************************************************************************
421REMARKS:
422Handles opcodes 0x05, 0x0d, 0x15, 0x1d, 0x25, 0x2d, 0x35, 0x3d
423****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000424static void x86emuOp_genop_word_AX_IMM(u8 op1)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000425{
426 u32 srcval;
427
428 op1 = (op1 >> 3) & 0x7;
429
430 START_OF_INSTR();
431 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
432 DECODE_PRINTF(x86emu_GenOpName[op1]);
433 DECODE_PRINTF("\tEAX,");
434 srcval = fetch_long_imm();
435 } else {
436 DECODE_PRINTF(x86emu_GenOpName[op1]);
437 DECODE_PRINTF("\tAX,");
438 srcval = fetch_word_imm();
439 }
440 DECODE_PRINTF2("%x\n", srcval);
441 TRACE_AND_STEP();
442 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
443 M.x86.R_EAX = genop_long_operation[op1](M.x86.R_EAX, srcval);
444 } else {
445 M.x86.R_AX = genop_word_operation[op1](M.x86.R_AX, (u16)srcval);
446 }
447 DECODE_CLEAR_SEGOVR();
448 END_OF_INSTR();
449}
450
451/****************************************************************************
452REMARKS:
453Handles opcode 0x06
454****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000455static void x86emuOp_push_ES(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000456{
457 START_OF_INSTR();
458 DECODE_PRINTF("PUSH\tES\n");
459 TRACE_AND_STEP();
460 push_word(M.x86.R_ES);
461 DECODE_CLEAR_SEGOVR();
462 END_OF_INSTR();
463}
464
465/****************************************************************************
466REMARKS:
467Handles opcode 0x07
468****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000469static void x86emuOp_pop_ES(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000470{
471 START_OF_INSTR();
472 DECODE_PRINTF("POP\tES\n");
473 TRACE_AND_STEP();
474 M.x86.R_ES = pop_word();
475 DECODE_CLEAR_SEGOVR();
476 END_OF_INSTR();
477}
478
479/****************************************************************************
480REMARKS:
481Handles opcode 0x0e
482****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000483static void x86emuOp_push_CS(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000484{
485 START_OF_INSTR();
486 DECODE_PRINTF("PUSH\tCS\n");
487 TRACE_AND_STEP();
488 push_word(M.x86.R_CS);
489 DECODE_CLEAR_SEGOVR();
490 END_OF_INSTR();
491}
492
493/****************************************************************************
494REMARKS:
495Handles opcode 0x0f. Escape for two-byte opcode (286 or better)
496****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000497static void x86emuOp_two_byte(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000498{
499 u8 op2 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++));
500 INC_DECODED_INST_LEN(1);
501 (*x86emu_optab2[op2])(op2);
502}
503
504/****************************************************************************
505REMARKS:
506Handles opcode 0x16
507****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000508static void x86emuOp_push_SS(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000509{
510 START_OF_INSTR();
511 DECODE_PRINTF("PUSH\tSS\n");
512 TRACE_AND_STEP();
513 push_word(M.x86.R_SS);
514 DECODE_CLEAR_SEGOVR();
515 END_OF_INSTR();
516}
517
518/****************************************************************************
519REMARKS:
520Handles opcode 0x17
521****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000522static void x86emuOp_pop_SS(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000523{
524 START_OF_INSTR();
525 DECODE_PRINTF("POP\tSS\n");
526 TRACE_AND_STEP();
527 M.x86.R_SS = pop_word();
528 DECODE_CLEAR_SEGOVR();
529 END_OF_INSTR();
530}
531
532/****************************************************************************
533REMARKS:
534Handles opcode 0x1e
535****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000536static void x86emuOp_push_DS(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000537{
538 START_OF_INSTR();
539 DECODE_PRINTF("PUSH\tDS\n");
540 TRACE_AND_STEP();
541 push_word(M.x86.R_DS);
542 DECODE_CLEAR_SEGOVR();
543 END_OF_INSTR();
544}
545
546/****************************************************************************
547REMARKS:
548Handles opcode 0x1f
549****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000550static void x86emuOp_pop_DS(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000551{
552 START_OF_INSTR();
553 DECODE_PRINTF("POP\tDS\n");
554 TRACE_AND_STEP();
555 M.x86.R_DS = pop_word();
556 DECODE_CLEAR_SEGOVR();
557 END_OF_INSTR();
558}
559
560/****************************************************************************
561REMARKS:
562Handles opcode 0x26
563****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000564static void x86emuOp_segovr_ES(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000565{
566 START_OF_INSTR();
567 DECODE_PRINTF("ES:\n");
568 TRACE_AND_STEP();
569 M.x86.mode |= SYSMODE_SEGOVR_ES;
570 /*
571 * note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4
572 * opcode subroutines we do not want to do this.
573 */
574 END_OF_INSTR();
575}
576
577/****************************************************************************
578REMARKS:
579Handles opcode 0x27
580****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000581static void x86emuOp_daa(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000582{
583 START_OF_INSTR();
584 DECODE_PRINTF("DAA\n");
585 TRACE_AND_STEP();
586 M.x86.R_AL = daa_byte(M.x86.R_AL);
587 DECODE_CLEAR_SEGOVR();
588 END_OF_INSTR();
589}
590
591/****************************************************************************
592REMARKS:
593Handles opcode 0x2e
594****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000595static void x86emuOp_segovr_CS(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000596{
597 START_OF_INSTR();
598 DECODE_PRINTF("CS:\n");
599 TRACE_AND_STEP();
600 M.x86.mode |= SYSMODE_SEGOVR_CS;
601 /* note no DECODE_CLEAR_SEGOVR here. */
602 END_OF_INSTR();
603}
604
605/****************************************************************************
606REMARKS:
607Handles opcode 0x2f
608****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000609static void x86emuOp_das(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000610{
611 START_OF_INSTR();
612 DECODE_PRINTF("DAS\n");
613 TRACE_AND_STEP();
614 M.x86.R_AL = das_byte(M.x86.R_AL);
615 DECODE_CLEAR_SEGOVR();
616 END_OF_INSTR();
617}
618
619/****************************************************************************
620REMARKS:
621Handles opcode 0x36
622****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000623static void x86emuOp_segovr_SS(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000624{
625 START_OF_INSTR();
626 DECODE_PRINTF("SS:\n");
627 TRACE_AND_STEP();
628 M.x86.mode |= SYSMODE_SEGOVR_SS;
629 /* no DECODE_CLEAR_SEGOVR ! */
630 END_OF_INSTR();
631}
632
633/****************************************************************************
634REMARKS:
635Handles opcode 0x37
636****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000637static void x86emuOp_aaa(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000638{
639 START_OF_INSTR();
640 DECODE_PRINTF("AAA\n");
641 TRACE_AND_STEP();
642 M.x86.R_AX = aaa_word(M.x86.R_AX);
643 DECODE_CLEAR_SEGOVR();
644 END_OF_INSTR();
645}
646
647/****************************************************************************
648REMARKS:
649Handles opcode 0x3e
650****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000651static void x86emuOp_segovr_DS(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000652{
653 START_OF_INSTR();
654 DECODE_PRINTF("DS:\n");
655 TRACE_AND_STEP();
656 M.x86.mode |= SYSMODE_SEGOVR_DS;
657 /* NO DECODE_CLEAR_SEGOVR! */
658 END_OF_INSTR();
659}
660
661/****************************************************************************
662REMARKS:
663Handles opcode 0x3f
664****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000665static void x86emuOp_aas(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000666{
667 START_OF_INSTR();
668 DECODE_PRINTF("AAS\n");
669 TRACE_AND_STEP();
670 M.x86.R_AX = aas_word(M.x86.R_AX);
671 DECODE_CLEAR_SEGOVR();
672 END_OF_INSTR();
673}
674
675/****************************************************************************
676REMARKS:
677Handles opcode 0x40 - 0x47
678****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000679static void x86emuOp_inc_register(u8 op1)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000680{
681 START_OF_INSTR();
682 op1 &= 0x7;
683 DECODE_PRINTF("INC\t");
684 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
685 u32 *reg;
686 reg = DECODE_RM_LONG_REGISTER(op1);
687 DECODE_PRINTF("\n");
688 TRACE_AND_STEP();
689 *reg = inc_long(*reg);
690 } else {
691 u16 *reg;
692 reg = DECODE_RM_WORD_REGISTER(op1);
693 DECODE_PRINTF("\n");
694 TRACE_AND_STEP();
695 *reg = inc_word(*reg);
696 }
697 DECODE_CLEAR_SEGOVR();
698 END_OF_INSTR();
699}
700
701/****************************************************************************
702REMARKS:
703Handles opcode 0x48 - 0x4F
704****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000705static void x86emuOp_dec_register(u8 op1)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000706{
707 START_OF_INSTR();
708 op1 &= 0x7;
709 DECODE_PRINTF("DEC\t");
710 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
711 u32 *reg;
712 reg = DECODE_RM_LONG_REGISTER(op1);
713 DECODE_PRINTF("\n");
714 TRACE_AND_STEP();
715 *reg = dec_long(*reg);
716 } else {
717 u16 *reg;
718 reg = DECODE_RM_WORD_REGISTER(op1);
719 DECODE_PRINTF("\n");
720 TRACE_AND_STEP();
721 *reg = dec_word(*reg);
722 }
723 DECODE_CLEAR_SEGOVR();
724 END_OF_INSTR();
725}
726
727/****************************************************************************
728REMARKS:
729Handles opcode 0x50 - 0x57
730****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000731static void x86emuOp_push_register(u8 op1)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000732{
733 START_OF_INSTR();
734 op1 &= 0x7;
735 DECODE_PRINTF("PUSH\t");
736 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
737 u32 *reg;
738 reg = DECODE_RM_LONG_REGISTER(op1);
739 DECODE_PRINTF("\n");
740 TRACE_AND_STEP();
741 push_long(*reg);
742 } else {
743 u16 *reg;
744 reg = DECODE_RM_WORD_REGISTER(op1);
745 DECODE_PRINTF("\n");
746 TRACE_AND_STEP();
747 push_word(*reg);
748 }
749 DECODE_CLEAR_SEGOVR();
750 END_OF_INSTR();
751}
752
753/****************************************************************************
754REMARKS:
755Handles opcode 0x58 - 0x5F
756****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000757static void x86emuOp_pop_register(u8 op1)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000758{
759 START_OF_INSTR();
760 op1 &= 0x7;
761 DECODE_PRINTF("POP\t");
762 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
763 u32 *reg;
764 reg = DECODE_RM_LONG_REGISTER(op1);
765 DECODE_PRINTF("\n");
766 TRACE_AND_STEP();
767 *reg = pop_long();
768 } else {
769 u16 *reg;
770 reg = DECODE_RM_WORD_REGISTER(op1);
771 DECODE_PRINTF("\n");
772 TRACE_AND_STEP();
773 *reg = pop_word();
774 }
775 DECODE_CLEAR_SEGOVR();
776 END_OF_INSTR();
777}
778
779/****************************************************************************
780REMARKS:
781Handles opcode 0x60
782****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000783static void x86emuOp_push_all(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000784{
785 START_OF_INSTR();
786 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
787 DECODE_PRINTF("PUSHAD\n");
788 } else {
789 DECODE_PRINTF("PUSHA\n");
790 }
791 TRACE_AND_STEP();
792 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
793 u32 old_sp = M.x86.R_ESP;
794
795 push_long(M.x86.R_EAX);
796 push_long(M.x86.R_ECX);
797 push_long(M.x86.R_EDX);
798 push_long(M.x86.R_EBX);
799 push_long(old_sp);
800 push_long(M.x86.R_EBP);
801 push_long(M.x86.R_ESI);
802 push_long(M.x86.R_EDI);
803 } else {
804 u16 old_sp = M.x86.R_SP;
805
806 push_word(M.x86.R_AX);
807 push_word(M.x86.R_CX);
808 push_word(M.x86.R_DX);
809 push_word(M.x86.R_BX);
810 push_word(old_sp);
811 push_word(M.x86.R_BP);
812 push_word(M.x86.R_SI);
813 push_word(M.x86.R_DI);
814 }
815 DECODE_CLEAR_SEGOVR();
816 END_OF_INSTR();
817}
818
819/****************************************************************************
820REMARKS:
821Handles opcode 0x61
822****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000823static void x86emuOp_pop_all(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000824{
825 START_OF_INSTR();
826 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
827 DECODE_PRINTF("POPAD\n");
828 } else {
829 DECODE_PRINTF("POPA\n");
830 }
831 TRACE_AND_STEP();
832 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
833 M.x86.R_EDI = pop_long();
834 M.x86.R_ESI = pop_long();
835 M.x86.R_EBP = pop_long();
836 M.x86.R_ESP += 4; /* skip ESP */
837 M.x86.R_EBX = pop_long();
838 M.x86.R_EDX = pop_long();
839 M.x86.R_ECX = pop_long();
840 M.x86.R_EAX = pop_long();
841 } else {
842 M.x86.R_DI = pop_word();
843 M.x86.R_SI = pop_word();
844 M.x86.R_BP = pop_word();
845 M.x86.R_SP += 2; /* skip SP */
846 M.x86.R_BX = pop_word();
847 M.x86.R_DX = pop_word();
848 M.x86.R_CX = pop_word();
849 M.x86.R_AX = pop_word();
850 }
851 DECODE_CLEAR_SEGOVR();
852 END_OF_INSTR();
853}
854
855/*opcode 0x62 ILLEGAL OP, calls x86emuOp_illegal_op() */
856/*opcode 0x63 ILLEGAL OP, calls x86emuOp_illegal_op() */
857
858/****************************************************************************
859REMARKS:
860Handles opcode 0x64
861****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000862static void x86emuOp_segovr_FS(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000863{
864 START_OF_INSTR();
865 DECODE_PRINTF("FS:\n");
866 TRACE_AND_STEP();
867 M.x86.mode |= SYSMODE_SEGOVR_FS;
868 /*
869 * note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4
870 * opcode subroutines we do not want to do this.
871 */
872 END_OF_INSTR();
873}
874
875/****************************************************************************
876REMARKS:
877Handles opcode 0x65
878****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000879static void x86emuOp_segovr_GS(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000880{
881 START_OF_INSTR();
882 DECODE_PRINTF("GS:\n");
883 TRACE_AND_STEP();
884 M.x86.mode |= SYSMODE_SEGOVR_GS;
885 /*
886 * note the lack of DECODE_CLEAR_SEGOVR(r) since, here is one of 4
887 * opcode subroutines we do not want to do this.
888 */
889 END_OF_INSTR();
890}
891
892/****************************************************************************
893REMARKS:
894Handles opcode 0x66 - prefix for 32-bit register
895****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000896static void x86emuOp_prefix_data(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000897{
898 START_OF_INSTR();
899 DECODE_PRINTF("DATA:\n");
900 TRACE_AND_STEP();
901 M.x86.mode |= SYSMODE_PREFIX_DATA;
902 /* note no DECODE_CLEAR_SEGOVR here. */
903 END_OF_INSTR();
904}
905
906/****************************************************************************
907REMARKS:
908Handles opcode 0x67 - prefix for 32-bit address
909****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000910static void x86emuOp_prefix_addr(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000911{
912 START_OF_INSTR();
913 DECODE_PRINTF("ADDR:\n");
914 TRACE_AND_STEP();
915 M.x86.mode |= SYSMODE_PREFIX_ADDR;
916 /* note no DECODE_CLEAR_SEGOVR here. */
917 END_OF_INSTR();
918}
919
920/****************************************************************************
921REMARKS:
922Handles opcode 0x68
923****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000924static void x86emuOp_push_word_IMM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000925{
926 u32 imm;
927
928 START_OF_INSTR();
929 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
930 imm = fetch_long_imm();
931 } else {
932 imm = fetch_word_imm();
933 }
934 DECODE_PRINTF2("PUSH\t%x\n", imm);
935 TRACE_AND_STEP();
936 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
937 push_long(imm);
938 } else {
939 push_word((u16)imm);
940 }
941 DECODE_CLEAR_SEGOVR();
942 END_OF_INSTR();
943}
944
945/****************************************************************************
946REMARKS:
947Handles opcode 0x69
948****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +0000949static void x86emuOp_imul_word_IMM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +0000950{
951 int mod, rl, rh;
952 uint srcoffset;
953
954 START_OF_INSTR();
955 DECODE_PRINTF("IMUL\t");
956 FETCH_DECODE_MODRM(mod, rh, rl);
957 if (mod < 3) {
958 srcoffset = decode_rmXX_address(mod, rl);
959 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
960 u32 *destreg;
961 u32 srcval;
962 u32 res_lo,res_hi;
963 s32 imm;
964
965 destreg = DECODE_RM_LONG_REGISTER(rh);
966 DECODE_PRINTF(",");
967 srcval = fetch_data_long(srcoffset);
968 imm = fetch_long_imm();
969 DECODE_PRINTF2(",%d\n", (s32)imm);
970 TRACE_AND_STEP();
971 imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm);
972 if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) ||
973 (((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) {
974 CLEAR_FLAG(F_CF);
975 CLEAR_FLAG(F_OF);
976 } else {
977 SET_FLAG(F_CF);
978 SET_FLAG(F_OF);
979 }
980 *destreg = (u32)res_lo;
981 } else {
982 u16 *destreg;
983 u16 srcval;
984 u32 res;
985 s16 imm;
986
987 destreg = DECODE_RM_WORD_REGISTER(rh);
988 DECODE_PRINTF(",");
989 srcval = fetch_data_word(srcoffset);
990 imm = fetch_word_imm();
991 DECODE_PRINTF2(",%d\n", (s32)imm);
992 TRACE_AND_STEP();
993 res = (s16)srcval * (s16)imm;
994 if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) ||
995 (((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) {
996 CLEAR_FLAG(F_CF);
997 CLEAR_FLAG(F_OF);
998 } else {
999 SET_FLAG(F_CF);
1000 SET_FLAG(F_OF);
1001 }
1002 *destreg = (u16)res;
1003 }
1004 } else { /* register to register */
1005 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1006 u32 *destreg,*srcreg;
1007 u32 res_lo,res_hi;
1008 s32 imm;
1009
1010 destreg = DECODE_RM_LONG_REGISTER(rh);
1011 DECODE_PRINTF(",");
1012 srcreg = DECODE_RM_LONG_REGISTER(rl);
1013 imm = fetch_long_imm();
1014 DECODE_PRINTF2(",%d\n", (s32)imm);
1015 TRACE_AND_STEP();
1016 imul_long_direct(&res_lo,&res_hi,(s32)*srcreg,(s32)imm);
1017 if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) ||
1018 (((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) {
1019 CLEAR_FLAG(F_CF);
1020 CLEAR_FLAG(F_OF);
1021 } else {
1022 SET_FLAG(F_CF);
1023 SET_FLAG(F_OF);
1024 }
1025 *destreg = (u32)res_lo;
1026 } else {
1027 u16 *destreg,*srcreg;
1028 u32 res;
1029 s16 imm;
1030
1031 destreg = DECODE_RM_WORD_REGISTER(rh);
1032 DECODE_PRINTF(",");
1033 srcreg = DECODE_RM_WORD_REGISTER(rl);
1034 imm = fetch_word_imm();
1035 DECODE_PRINTF2(",%d\n", (s32)imm);
1036 res = (s16)*srcreg * (s16)imm;
1037 if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) ||
1038 (((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) {
1039 CLEAR_FLAG(F_CF);
1040 CLEAR_FLAG(F_OF);
1041 } else {
1042 SET_FLAG(F_CF);
1043 SET_FLAG(F_OF);
1044 }
1045 *destreg = (u16)res;
1046 }
1047 }
1048 DECODE_CLEAR_SEGOVR();
1049 END_OF_INSTR();
1050}
1051
1052/****************************************************************************
1053REMARKS:
1054Handles opcode 0x6a
1055****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001056static void x86emuOp_push_byte_IMM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001057{
1058 s16 imm;
1059
1060 START_OF_INSTR();
1061 imm = (s8)fetch_byte_imm();
1062 DECODE_PRINTF2("PUSH\t%d\n", imm);
1063 TRACE_AND_STEP();
1064 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1065 push_long(imm);
1066 } else {
1067 push_word(imm);
1068 }
1069 DECODE_CLEAR_SEGOVR();
1070 END_OF_INSTR();
1071}
1072
1073/****************************************************************************
1074REMARKS:
1075Handles opcode 0x6b
1076****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001077static void x86emuOp_imul_byte_IMM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001078{
1079 int mod, rl, rh;
1080 uint srcoffset;
1081 s8 imm;
1082
1083 START_OF_INSTR();
1084 DECODE_PRINTF("IMUL\t");
1085 FETCH_DECODE_MODRM(mod, rh, rl);
1086 if (mod < 3) {
1087 srcoffset = decode_rmXX_address(mod, rl);
1088 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1089 u32 *destreg;
1090 u32 srcval;
1091 u32 res_lo,res_hi;
1092
1093 destreg = DECODE_RM_LONG_REGISTER(rh);
1094 DECODE_PRINTF(",");
1095 srcval = fetch_data_long(srcoffset);
1096 imm = fetch_byte_imm();
1097 DECODE_PRINTF2(",%d\n", (s32)imm);
1098 TRACE_AND_STEP();
1099 imul_long_direct(&res_lo,&res_hi,(s32)srcval,(s32)imm);
1100 if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) ||
1101 (((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) {
1102 CLEAR_FLAG(F_CF);
1103 CLEAR_FLAG(F_OF);
1104 } else {
1105 SET_FLAG(F_CF);
1106 SET_FLAG(F_OF);
1107 }
1108 *destreg = (u32)res_lo;
1109 } else {
1110 u16 *destreg;
1111 u16 srcval;
1112 u32 res;
1113
1114 destreg = DECODE_RM_WORD_REGISTER(rh);
1115 DECODE_PRINTF(",");
1116 srcval = fetch_data_word(srcoffset);
1117 imm = fetch_byte_imm();
1118 DECODE_PRINTF2(",%d\n", (s32)imm);
1119 TRACE_AND_STEP();
1120 res = (s16)srcval * (s16)imm;
1121 if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) ||
1122 (((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) {
1123 CLEAR_FLAG(F_CF);
1124 CLEAR_FLAG(F_OF);
1125 } else {
1126 SET_FLAG(F_CF);
1127 SET_FLAG(F_OF);
1128 }
1129 *destreg = (u16)res;
1130 }
1131 } else { /* register to register */
1132 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1133 u32 *destreg,*srcreg;
1134 u32 res_lo,res_hi;
1135
1136 destreg = DECODE_RM_LONG_REGISTER(rh);
1137 DECODE_PRINTF(",");
1138 srcreg = DECODE_RM_LONG_REGISTER(rl);
1139 imm = fetch_byte_imm();
1140 DECODE_PRINTF2(",%d\n", (s32)imm);
1141 TRACE_AND_STEP();
1142 imul_long_direct(&res_lo,&res_hi,(s32)*srcreg,(s32)imm);
1143 if ((((res_lo & 0x80000000) == 0) && (res_hi == 0x00000000)) ||
1144 (((res_lo & 0x80000000) != 0) && (res_hi == 0xFFFFFFFF))) {
1145 CLEAR_FLAG(F_CF);
1146 CLEAR_FLAG(F_OF);
1147 } else {
1148 SET_FLAG(F_CF);
1149 SET_FLAG(F_OF);
1150 }
1151 *destreg = (u32)res_lo;
1152 } else {
1153 u16 *destreg,*srcreg;
1154 u32 res;
1155
1156 destreg = DECODE_RM_WORD_REGISTER(rh);
1157 DECODE_PRINTF(",");
1158 srcreg = DECODE_RM_WORD_REGISTER(rl);
1159 imm = fetch_byte_imm();
1160 DECODE_PRINTF2(",%d\n", (s32)imm);
1161 TRACE_AND_STEP();
1162 res = (s16)*srcreg * (s16)imm;
1163 if ((((res & 0x8000) == 0) && ((res >> 16) == 0x0000)) ||
1164 (((res & 0x8000) != 0) && ((res >> 16) == 0xFFFF))) {
1165 CLEAR_FLAG(F_CF);
1166 CLEAR_FLAG(F_OF);
1167 } else {
1168 SET_FLAG(F_CF);
1169 SET_FLAG(F_OF);
1170 }
1171 *destreg = (u16)res;
1172 }
1173 }
1174 DECODE_CLEAR_SEGOVR();
1175 END_OF_INSTR();
1176}
1177
1178/****************************************************************************
1179REMARKS:
1180Handles opcode 0x6c
1181****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001182static void x86emuOp_ins_byte(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001183{
1184 START_OF_INSTR();
1185 DECODE_PRINTF("INSB\n");
1186 ins(1);
1187 TRACE_AND_STEP();
1188 DECODE_CLEAR_SEGOVR();
1189 END_OF_INSTR();
1190}
1191
1192/****************************************************************************
1193REMARKS:
1194Handles opcode 0x6d
1195****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001196static void x86emuOp_ins_word(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001197{
1198 START_OF_INSTR();
1199 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1200 DECODE_PRINTF("INSD\n");
1201 ins(4);
1202 } else {
1203 DECODE_PRINTF("INSW\n");
1204 ins(2);
1205 }
1206 TRACE_AND_STEP();
1207 DECODE_CLEAR_SEGOVR();
1208 END_OF_INSTR();
1209}
1210
1211/****************************************************************************
1212REMARKS:
1213Handles opcode 0x6e
1214****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001215static void x86emuOp_outs_byte(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001216{
1217 START_OF_INSTR();
1218 DECODE_PRINTF("OUTSB\n");
1219 outs(1);
1220 TRACE_AND_STEP();
1221 DECODE_CLEAR_SEGOVR();
1222 END_OF_INSTR();
1223}
1224
1225/****************************************************************************
1226REMARKS:
1227Handles opcode 0x6f
1228****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001229static void x86emuOp_outs_word(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001230{
1231 START_OF_INSTR();
1232 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1233 DECODE_PRINTF("OUTSD\n");
1234 outs(4);
1235 } else {
1236 DECODE_PRINTF("OUTSW\n");
1237 outs(2);
1238 }
1239 TRACE_AND_STEP();
1240 DECODE_CLEAR_SEGOVR();
1241 END_OF_INSTR();
1242}
1243
1244/****************************************************************************
1245REMARKS:
1246Handles opcode 0x70 - 0x7F
1247****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001248static void x86emuOp_jump_near_cond(u8 op1)
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001249{
1250 s8 offset;
1251 u16 target;
1252 int cond;
1253
1254 /* jump to byte offset if overflow flag is set */
1255 START_OF_INSTR();
1256 cond = x86emu_check_jump_condition(op1 & 0xF);
1257 offset = (s8)fetch_byte_imm();
1258 target = (u16)(M.x86.R_IP + (s16)offset);
1259 DECODE_PRINTF2("%x\n", target);
1260 TRACE_AND_STEP();
1261 if (cond) {
1262 M.x86.R_IP = target;
1263 JMP_TRACE(M.x86.saved_cs, M.x86.saved_ip, M.x86.R_CS, M.x86.R_IP, " NEAR COND ");
1264 }
1265 DECODE_CLEAR_SEGOVR();
1266 END_OF_INSTR();
1267}
1268
1269/****************************************************************************
1270REMARKS:
1271Handles opcode 0x80
1272****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001273static void x86emuOp_opc80_byte_RM_IMM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001274{
1275 int mod, rl, rh;
1276 u8 *destreg;
1277 uint destoffset;
1278 u8 imm;
1279 u8 destval;
1280
1281 /*
1282 * Weirdo special case instruction format. Part of the opcode
1283 * held below in "RH". Doubly nested case would result, except
1284 * that the decoded instruction
1285 */
1286 START_OF_INSTR();
1287 FETCH_DECODE_MODRM(mod, rh, rl);
Myles Watson8e9234f2010-02-19 19:08:11 +00001288#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001289 if (DEBUG_DECODE()) {
1290 /* XXX DECODE_PRINTF may be changed to something more
1291 general, so that it is important to leave the strings
1292 in the same format, even though the result is that the
1293 above test is done twice. */
1294
1295 switch (rh) {
1296 case 0:
1297 DECODE_PRINTF("ADD\t");
1298 break;
1299 case 1:
1300 DECODE_PRINTF("OR\t");
1301 break;
1302 case 2:
1303 DECODE_PRINTF("ADC\t");
1304 break;
1305 case 3:
1306 DECODE_PRINTF("SBB\t");
1307 break;
1308 case 4:
1309 DECODE_PRINTF("AND\t");
1310 break;
1311 case 5:
1312 DECODE_PRINTF("SUB\t");
1313 break;
1314 case 6:
1315 DECODE_PRINTF("XOR\t");
1316 break;
1317 case 7:
1318 DECODE_PRINTF("CMP\t");
1319 break;
1320 }
1321 }
1322#endif
1323 /* know operation, decode the mod byte to find the addressing
1324 mode. */
1325 if (mod < 3) {
1326 DECODE_PRINTF("BYTE PTR ");
1327 destoffset = decode_rmXX_address(mod, rl);
1328 DECODE_PRINTF(",");
1329 destval = fetch_data_byte(destoffset);
1330 imm = fetch_byte_imm();
1331 DECODE_PRINTF2("%x\n", imm);
1332 TRACE_AND_STEP();
1333 destval = (*genop_byte_operation[rh]) (destval, imm);
1334 if (rh != 7)
1335 store_data_byte(destoffset, destval);
1336 } else { /* register to register */
1337 destreg = DECODE_RM_BYTE_REGISTER(rl);
1338 DECODE_PRINTF(",");
1339 imm = fetch_byte_imm();
1340 DECODE_PRINTF2("%x\n", imm);
1341 TRACE_AND_STEP();
1342 *destreg = (*genop_byte_operation[rh]) (*destreg, imm);
1343 }
1344 DECODE_CLEAR_SEGOVR();
1345 END_OF_INSTR();
1346}
1347
1348/****************************************************************************
1349REMARKS:
1350Handles opcode 0x81
1351****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001352static void x86emuOp_opc81_word_RM_IMM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001353{
1354 int mod, rl, rh;
1355 uint destoffset;
1356
1357 /*
1358 * Weirdo special case instruction format. Part of the opcode
1359 * held below in "RH". Doubly nested case would result, except
1360 * that the decoded instruction
1361 */
1362 START_OF_INSTR();
1363 FETCH_DECODE_MODRM(mod, rh, rl);
Myles Watson8e9234f2010-02-19 19:08:11 +00001364#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001365 if (DEBUG_DECODE()) {
1366 /* XXX DECODE_PRINTF may be changed to something more
1367 general, so that it is important to leave the strings
1368 in the same format, even though the result is that the
1369 above test is done twice. */
1370
1371 switch (rh) {
1372 case 0:
1373 DECODE_PRINTF("ADD\t");
1374 break;
1375 case 1:
1376 DECODE_PRINTF("OR\t");
1377 break;
1378 case 2:
1379 DECODE_PRINTF("ADC\t");
1380 break;
1381 case 3:
1382 DECODE_PRINTF("SBB\t");
1383 break;
1384 case 4:
1385 DECODE_PRINTF("AND\t");
1386 break;
1387 case 5:
1388 DECODE_PRINTF("SUB\t");
1389 break;
1390 case 6:
1391 DECODE_PRINTF("XOR\t");
1392 break;
1393 case 7:
1394 DECODE_PRINTF("CMP\t");
1395 break;
1396 }
1397 }
1398#endif
1399 /*
1400 * Know operation, decode the mod byte to find the addressing
1401 * mode.
1402 */
1403 if (mod < 3) {
1404 DECODE_PRINTF("DWORD PTR ");
1405 destoffset = decode_rmXX_address(mod, rl);
1406 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1407 u32 destval,imm;
1408
1409 DECODE_PRINTF(",");
1410 destval = fetch_data_long(destoffset);
1411 imm = fetch_long_imm();
1412 DECODE_PRINTF2("%x\n", imm);
1413 TRACE_AND_STEP();
1414 destval = (*genop_long_operation[rh]) (destval, imm);
1415 if (rh != 7)
1416 store_data_long(destoffset, destval);
1417 } else {
1418 u16 destval,imm;
1419
1420 DECODE_PRINTF(",");
1421 destval = fetch_data_word(destoffset);
1422 imm = fetch_word_imm();
1423 DECODE_PRINTF2("%x\n", imm);
1424 TRACE_AND_STEP();
1425 destval = (*genop_word_operation[rh]) (destval, imm);
1426 if (rh != 7)
1427 store_data_word(destoffset, destval);
1428 }
1429 } else { /* register to register */
1430 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1431 u32 *destreg, imm;
1432
1433 destreg = DECODE_RM_LONG_REGISTER(rl);
1434 DECODE_PRINTF(",");
1435 imm = fetch_long_imm();
1436 DECODE_PRINTF2("%x\n", imm);
1437 TRACE_AND_STEP();
1438 *destreg = (*genop_long_operation[rh]) (*destreg, imm);
1439 } else {
1440 u16 *destreg, imm;
1441
1442 destreg = DECODE_RM_WORD_REGISTER(rl);
1443 DECODE_PRINTF(",");
1444 imm = fetch_word_imm();
1445 DECODE_PRINTF2("%x\n", imm);
1446 TRACE_AND_STEP();
1447 *destreg = (*genop_word_operation[rh]) (*destreg, imm);
1448 }
1449 }
1450 DECODE_CLEAR_SEGOVR();
1451 END_OF_INSTR();
1452}
1453
1454/****************************************************************************
1455REMARKS:
1456Handles opcode 0x82
1457****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001458static void x86emuOp_opc82_byte_RM_IMM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001459{
1460 int mod, rl, rh;
1461 u8 *destreg;
1462 uint destoffset;
1463 u8 imm;
1464 u8 destval;
1465
1466 /*
1467 * Weirdo special case instruction format. Part of the opcode
1468 * held below in "RH". Doubly nested case would result, except
1469 * that the decoded instruction Similar to opcode 81, except that
1470 * the immediate byte is sign extended to a word length.
1471 */
1472 START_OF_INSTR();
1473 FETCH_DECODE_MODRM(mod, rh, rl);
Myles Watson8e9234f2010-02-19 19:08:11 +00001474#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001475 if (DEBUG_DECODE()) {
1476 /* XXX DECODE_PRINTF may be changed to something more
1477 general, so that it is important to leave the strings
1478 in the same format, even though the result is that the
1479 above test is done twice. */
1480 switch (rh) {
1481 case 0:
1482 DECODE_PRINTF("ADD\t");
1483 break;
1484 case 1:
1485 DECODE_PRINTF("OR\t");
1486 break;
1487 case 2:
1488 DECODE_PRINTF("ADC\t");
1489 break;
1490 case 3:
1491 DECODE_PRINTF("SBB\t");
1492 break;
1493 case 4:
1494 DECODE_PRINTF("AND\t");
1495 break;
1496 case 5:
1497 DECODE_PRINTF("SUB\t");
1498 break;
1499 case 6:
1500 DECODE_PRINTF("XOR\t");
1501 break;
1502 case 7:
1503 DECODE_PRINTF("CMP\t");
1504 break;
1505 }
1506 }
1507#endif
1508 /* know operation, decode the mod byte to find the addressing
1509 mode. */
1510 if (mod < 3) {
1511 DECODE_PRINTF("BYTE PTR ");
1512 destoffset = decode_rmXX_address(mod, rl);
1513 destval = fetch_data_byte(destoffset);
1514 imm = fetch_byte_imm();
1515 DECODE_PRINTF2(",%x\n", imm);
1516 TRACE_AND_STEP();
1517 destval = (*genop_byte_operation[rh]) (destval, imm);
1518 if (rh != 7)
1519 store_data_byte(destoffset, destval);
1520 } else { /* register to register */
1521 destreg = DECODE_RM_BYTE_REGISTER(rl);
1522 imm = fetch_byte_imm();
1523 DECODE_PRINTF2(",%x\n", imm);
1524 TRACE_AND_STEP();
1525 *destreg = (*genop_byte_operation[rh]) (*destreg, imm);
1526 }
1527 DECODE_CLEAR_SEGOVR();
1528 END_OF_INSTR();
1529}
1530
1531/****************************************************************************
1532REMARKS:
1533Handles opcode 0x83
1534****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001535static void x86emuOp_opc83_word_RM_IMM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001536{
1537 int mod, rl, rh;
1538 uint destoffset;
1539
1540 /*
1541 * Weirdo special case instruction format. Part of the opcode
1542 * held below in "RH". Doubly nested case would result, except
1543 * that the decoded instruction Similar to opcode 81, except that
1544 * the immediate byte is sign extended to a word length.
1545 */
1546 START_OF_INSTR();
1547 FETCH_DECODE_MODRM(mod, rh, rl);
Myles Watson8e9234f2010-02-19 19:08:11 +00001548#ifdef DEBUG
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001549 if (DEBUG_DECODE()) {
1550 /* XXX DECODE_PRINTF may be changed to something more
1551 general, so that it is important to leave the strings
1552 in the same format, even though the result is that the
1553 above test is done twice. */
1554 switch (rh) {
1555 case 0:
1556 DECODE_PRINTF("ADD\t");
1557 break;
1558 case 1:
1559 DECODE_PRINTF("OR\t");
1560 break;
1561 case 2:
1562 DECODE_PRINTF("ADC\t");
1563 break;
1564 case 3:
1565 DECODE_PRINTF("SBB\t");
1566 break;
1567 case 4:
1568 DECODE_PRINTF("AND\t");
1569 break;
1570 case 5:
1571 DECODE_PRINTF("SUB\t");
1572 break;
1573 case 6:
1574 DECODE_PRINTF("XOR\t");
1575 break;
1576 case 7:
1577 DECODE_PRINTF("CMP\t");
1578 break;
1579 }
1580 }
1581#endif
1582 /* know operation, decode the mod byte to find the addressing
1583 mode. */
1584 if (mod < 3) {
1585 DECODE_PRINTF("DWORD PTR ");
1586 destoffset = decode_rmXX_address(mod,rl);
1587
1588 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1589 u32 destval,imm;
1590
1591 destval = fetch_data_long(destoffset);
1592 imm = (s8) fetch_byte_imm();
1593 DECODE_PRINTF2(",%x\n", imm);
1594 TRACE_AND_STEP();
1595 destval = (*genop_long_operation[rh]) (destval, imm);
1596 if (rh != 7)
1597 store_data_long(destoffset, destval);
1598 } else {
1599 u16 destval,imm;
1600
1601 destval = fetch_data_word(destoffset);
1602 imm = (s8) fetch_byte_imm();
1603 DECODE_PRINTF2(",%x\n", imm);
1604 TRACE_AND_STEP();
1605 destval = (*genop_word_operation[rh]) (destval, imm);
1606 if (rh != 7)
1607 store_data_word(destoffset, destval);
1608 }
1609 } else { /* register to register */
1610 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1611 u32 *destreg, imm;
1612
1613 destreg = DECODE_RM_LONG_REGISTER(rl);
1614 imm = (s8) fetch_byte_imm();
1615 DECODE_PRINTF2(",%x\n", imm);
1616 TRACE_AND_STEP();
1617 *destreg = (*genop_long_operation[rh]) (*destreg, imm);
1618 } else {
1619 u16 *destreg, imm;
1620
1621 destreg = DECODE_RM_WORD_REGISTER(rl);
1622 imm = (s8) fetch_byte_imm();
1623 DECODE_PRINTF2(",%x\n", imm);
1624 TRACE_AND_STEP();
1625 *destreg = (*genop_word_operation[rh]) (*destreg, imm);
1626 }
1627 }
1628 DECODE_CLEAR_SEGOVR();
1629 END_OF_INSTR();
1630}
1631
1632/****************************************************************************
1633REMARKS:
1634Handles opcode 0x84
1635****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001636static void x86emuOp_test_byte_RM_R(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001637{
1638 int mod, rl, rh;
1639 u8 *destreg, *srcreg;
1640 uint destoffset;
1641 u8 destval;
1642
1643 START_OF_INSTR();
1644 DECODE_PRINTF("TEST\t");
1645 FETCH_DECODE_MODRM(mod, rh, rl);
1646 if (mod < 3) {
1647 destoffset = decode_rmXX_address(mod, rl);
1648 DECODE_PRINTF(",");
1649 destval = fetch_data_byte(destoffset);
1650 srcreg = DECODE_RM_BYTE_REGISTER(rh);
1651 DECODE_PRINTF("\n");
1652 TRACE_AND_STEP();
1653 test_byte(destval, *srcreg);
1654 } else { /* register to register */
1655 destreg = DECODE_RM_BYTE_REGISTER(rl);
1656 DECODE_PRINTF(",");
1657 srcreg = DECODE_RM_BYTE_REGISTER(rh);
1658 DECODE_PRINTF("\n");
1659 TRACE_AND_STEP();
1660 test_byte(*destreg, *srcreg);
1661 }
1662 DECODE_CLEAR_SEGOVR();
1663 END_OF_INSTR();
1664}
1665
1666/****************************************************************************
1667REMARKS:
1668Handles opcode 0x85
1669****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001670static void x86emuOp_test_word_RM_R(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001671{
1672 int mod, rl, rh;
1673 uint destoffset;
1674
1675 START_OF_INSTR();
1676 DECODE_PRINTF("TEST\t");
1677 FETCH_DECODE_MODRM(mod, rh, rl);
1678 if (mod < 3) {
1679 destoffset = decode_rmXX_address(mod, rl);
1680 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1681 u32 destval;
1682 u32 *srcreg;
1683
1684 DECODE_PRINTF(",");
1685 destval = fetch_data_long(destoffset);
1686 srcreg = DECODE_RM_LONG_REGISTER(rh);
1687 DECODE_PRINTF("\n");
1688 TRACE_AND_STEP();
1689 test_long(destval, *srcreg);
1690 } else {
1691 u16 destval;
1692 u16 *srcreg;
1693
1694 DECODE_PRINTF(",");
1695 destval = fetch_data_word(destoffset);
1696 srcreg = DECODE_RM_WORD_REGISTER(rh);
1697 DECODE_PRINTF("\n");
1698 TRACE_AND_STEP();
1699 test_word(destval, *srcreg);
1700 }
1701 } else { /* register to register */
1702 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1703 u32 *destreg,*srcreg;
1704
1705 destreg = DECODE_RM_LONG_REGISTER(rl);
1706 DECODE_PRINTF(",");
1707 srcreg = DECODE_RM_LONG_REGISTER(rh);
1708 DECODE_PRINTF("\n");
1709 TRACE_AND_STEP();
1710 test_long(*destreg, *srcreg);
1711 } else {
1712 u16 *destreg,*srcreg;
1713
1714 destreg = DECODE_RM_WORD_REGISTER(rl);
1715 DECODE_PRINTF(",");
1716 srcreg = DECODE_RM_WORD_REGISTER(rh);
1717 DECODE_PRINTF("\n");
1718 TRACE_AND_STEP();
1719 test_word(*destreg, *srcreg);
1720 }
1721 }
1722 DECODE_CLEAR_SEGOVR();
1723 END_OF_INSTR();
1724}
1725
1726/****************************************************************************
1727REMARKS:
1728Handles opcode 0x86
1729****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001730static void x86emuOp_xchg_byte_RM_R(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001731{
1732 int mod, rl, rh;
1733 u8 *destreg, *srcreg;
1734 uint destoffset;
1735 u8 destval;
1736 u8 tmp;
1737
1738 START_OF_INSTR();
1739 DECODE_PRINTF("XCHG\t");
1740 FETCH_DECODE_MODRM(mod, rh, rl);
1741 if (mod < 3) {
1742 destoffset = decode_rmXX_address(mod, rl);
1743 DECODE_PRINTF(",");
1744 destval = fetch_data_byte(destoffset);
1745 srcreg = DECODE_RM_BYTE_REGISTER(rh);
1746 DECODE_PRINTF("\n");
1747 TRACE_AND_STEP();
1748 tmp = *srcreg;
1749 *srcreg = destval;
1750 destval = tmp;
1751 store_data_byte(destoffset, destval);
1752 } else { /* register to register */
1753 destreg = DECODE_RM_BYTE_REGISTER(rl);
1754 DECODE_PRINTF(",");
1755 srcreg = DECODE_RM_BYTE_REGISTER(rh);
1756 DECODE_PRINTF("\n");
1757 TRACE_AND_STEP();
1758 tmp = *srcreg;
1759 *srcreg = *destreg;
1760 *destreg = tmp;
1761 }
1762 DECODE_CLEAR_SEGOVR();
1763 END_OF_INSTR();
1764}
1765
1766/****************************************************************************
1767REMARKS:
1768Handles opcode 0x87
1769****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001770static void x86emuOp_xchg_word_RM_R(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001771{
1772 int mod, rl, rh;
1773 uint destoffset;
1774
1775 START_OF_INSTR();
1776 DECODE_PRINTF("XCHG\t");
1777 FETCH_DECODE_MODRM(mod, rh, rl);
1778 if (mod < 3) {
1779 destoffset = decode_rmXX_address(mod, rl);
1780 DECODE_PRINTF(",");
1781 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1782 u32 *srcreg;
1783 u32 destval,tmp;
1784
1785 destval = fetch_data_long(destoffset);
1786 srcreg = DECODE_RM_LONG_REGISTER(rh);
1787 DECODE_PRINTF("\n");
1788 TRACE_AND_STEP();
1789 tmp = *srcreg;
1790 *srcreg = destval;
1791 destval = tmp;
1792 store_data_long(destoffset, destval);
1793 } else {
1794 u16 *srcreg;
1795 u16 destval,tmp;
1796
1797 destval = fetch_data_word(destoffset);
1798 srcreg = DECODE_RM_WORD_REGISTER(rh);
1799 DECODE_PRINTF("\n");
1800 TRACE_AND_STEP();
1801 tmp = *srcreg;
1802 *srcreg = destval;
1803 destval = tmp;
1804 store_data_word(destoffset, destval);
1805 }
1806 } else { /* register to register */
1807 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1808 u32 *destreg,*srcreg;
1809 u32 tmp;
1810
1811 destreg = DECODE_RM_LONG_REGISTER(rl);
1812 DECODE_PRINTF(",");
1813 srcreg = DECODE_RM_LONG_REGISTER(rh);
1814 DECODE_PRINTF("\n");
1815 TRACE_AND_STEP();
1816 tmp = *srcreg;
1817 *srcreg = *destreg;
1818 *destreg = tmp;
1819 } else {
1820 u16 *destreg,*srcreg;
1821 u16 tmp;
1822
1823 destreg = DECODE_RM_WORD_REGISTER(rl);
1824 DECODE_PRINTF(",");
1825 srcreg = DECODE_RM_WORD_REGISTER(rh);
1826 DECODE_PRINTF("\n");
1827 TRACE_AND_STEP();
1828 tmp = *srcreg;
1829 *srcreg = *destreg;
1830 *destreg = tmp;
1831 }
1832 }
1833 DECODE_CLEAR_SEGOVR();
1834 END_OF_INSTR();
1835}
1836
1837/****************************************************************************
1838REMARKS:
1839Handles opcode 0x88
1840****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001841static void x86emuOp_mov_byte_RM_R(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001842{
1843 int mod, rl, rh;
1844 u8 *destreg, *srcreg;
1845 uint destoffset;
1846
1847 START_OF_INSTR();
1848 DECODE_PRINTF("MOV\t");
1849 FETCH_DECODE_MODRM(mod, rh, rl);
1850 if (mod < 3) {
1851 destoffset = decode_rmXX_address(mod, rl);
1852 DECODE_PRINTF(",");
1853 srcreg = DECODE_RM_BYTE_REGISTER(rh);
1854 DECODE_PRINTF("\n");
1855 TRACE_AND_STEP();
1856 store_data_byte(destoffset, *srcreg);
1857 } else { /* register to register */
1858 destreg = DECODE_RM_BYTE_REGISTER(rl);
1859 DECODE_PRINTF(",");
1860 srcreg = DECODE_RM_BYTE_REGISTER(rh);
1861 DECODE_PRINTF("\n");
1862 TRACE_AND_STEP();
1863 *destreg = *srcreg;
1864 }
1865 DECODE_CLEAR_SEGOVR();
1866 END_OF_INSTR();
1867}
1868
1869/****************************************************************************
1870REMARKS:
1871Handles opcode 0x89
1872****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001873static void x86emuOp_mov_word_RM_R(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001874{
1875 int mod, rl, rh;
1876 uint destoffset;
1877
1878 START_OF_INSTR();
1879 DECODE_PRINTF("MOV\t");
1880 FETCH_DECODE_MODRM(mod, rh, rl);
1881 if (mod < 3) {
1882 destoffset = decode_rmXX_address(mod, rl);
1883 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1884 u32 *srcreg;
1885
1886 DECODE_PRINTF(",");
1887 srcreg = DECODE_RM_LONG_REGISTER(rh);
1888 DECODE_PRINTF("\n");
1889 TRACE_AND_STEP();
1890 store_data_long(destoffset, *srcreg);
1891 } else {
1892 u16 *srcreg;
1893
1894 DECODE_PRINTF(",");
1895 srcreg = DECODE_RM_WORD_REGISTER(rh);
1896 DECODE_PRINTF("\n");
1897 TRACE_AND_STEP();
1898 store_data_word(destoffset, *srcreg);
1899 }
1900 } else { /* register to register */
1901 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1902 u32 *destreg,*srcreg;
1903
1904 destreg = DECODE_RM_LONG_REGISTER(rl);
1905 DECODE_PRINTF(",");
1906 srcreg = DECODE_RM_LONG_REGISTER(rh);
1907 DECODE_PRINTF("\n");
1908 TRACE_AND_STEP();
1909 *destreg = *srcreg;
1910 } else {
1911 u16 *destreg,*srcreg;
1912
1913 destreg = DECODE_RM_WORD_REGISTER(rl);
1914 DECODE_PRINTF(",");
1915 srcreg = DECODE_RM_WORD_REGISTER(rh);
1916 DECODE_PRINTF("\n");
1917 TRACE_AND_STEP();
1918 *destreg = *srcreg;
1919 }
1920 }
1921 DECODE_CLEAR_SEGOVR();
1922 END_OF_INSTR();
1923}
1924
1925/****************************************************************************
1926REMARKS:
1927Handles opcode 0x8a
1928****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001929static void x86emuOp_mov_byte_R_RM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001930{
1931 int mod, rl, rh;
1932 u8 *destreg, *srcreg;
1933 uint srcoffset;
1934 u8 srcval;
1935
1936 START_OF_INSTR();
1937 DECODE_PRINTF("MOV\t");
1938 FETCH_DECODE_MODRM(mod, rh, rl);
1939 if (mod < 3) {
1940 destreg = DECODE_RM_BYTE_REGISTER(rh);
1941 DECODE_PRINTF(",");
1942 srcoffset = decode_rmXX_address(mod, rl);
1943 srcval = fetch_data_byte(srcoffset);
1944 DECODE_PRINTF("\n");
1945 TRACE_AND_STEP();
1946 *destreg = srcval;
1947 } else { /* register to register */
1948 destreg = DECODE_RM_BYTE_REGISTER(rh);
1949 DECODE_PRINTF(",");
1950 srcreg = DECODE_RM_BYTE_REGISTER(rl);
1951 DECODE_PRINTF("\n");
1952 TRACE_AND_STEP();
1953 *destreg = *srcreg;
1954 }
1955 DECODE_CLEAR_SEGOVR();
1956 END_OF_INSTR();
1957}
1958
1959/****************************************************************************
1960REMARKS:
1961Handles opcode 0x8b
1962****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00001963static void x86emuOp_mov_word_R_RM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00001964{
1965 int mod, rl, rh;
1966 uint srcoffset;
1967
1968 START_OF_INSTR();
1969 DECODE_PRINTF("MOV\t");
1970 FETCH_DECODE_MODRM(mod, rh, rl);
1971 if (mod < 3) {
1972 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1973 u32 *destreg;
1974 u32 srcval;
1975
1976 destreg = DECODE_RM_LONG_REGISTER(rh);
1977 DECODE_PRINTF(",");
1978 srcoffset = decode_rmXX_address(mod, rl);
1979 srcval = fetch_data_long(srcoffset);
1980 DECODE_PRINTF("\n");
1981 TRACE_AND_STEP();
1982 *destreg = srcval;
1983 } else {
1984 u16 *destreg;
1985 u16 srcval;
1986
1987 destreg = DECODE_RM_WORD_REGISTER(rh);
1988 DECODE_PRINTF(",");
1989 srcoffset = decode_rmXX_address(mod, rl);
1990 srcval = fetch_data_word(srcoffset);
1991 DECODE_PRINTF("\n");
1992 TRACE_AND_STEP();
1993 *destreg = srcval;
1994 }
1995 } else { /* register to register */
1996 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
1997 u32 *destreg, *srcreg;
1998
1999 destreg = DECODE_RM_LONG_REGISTER(rh);
2000 DECODE_PRINTF(",");
2001 srcreg = DECODE_RM_LONG_REGISTER(rl);
2002 DECODE_PRINTF("\n");
2003 TRACE_AND_STEP();
2004 *destreg = *srcreg;
2005 } else {
2006 u16 *destreg, *srcreg;
2007
2008 destreg = DECODE_RM_WORD_REGISTER(rh);
2009 DECODE_PRINTF(",");
2010 srcreg = DECODE_RM_WORD_REGISTER(rl);
2011 DECODE_PRINTF("\n");
2012 TRACE_AND_STEP();
2013 *destreg = *srcreg;
2014 }
2015 }
2016 DECODE_CLEAR_SEGOVR();
2017 END_OF_INSTR();
2018}
2019
2020/****************************************************************************
2021REMARKS:
2022Handles opcode 0x8c
2023****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002024static void x86emuOp_mov_word_RM_SR(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002025{
2026 int mod, rl, rh;
2027 u16 *destreg, *srcreg;
2028 uint destoffset;
2029 u16 destval;
2030
2031 START_OF_INSTR();
2032 DECODE_PRINTF("MOV\t");
2033 FETCH_DECODE_MODRM(mod, rh, rl);
2034 if (mod < 3) {
2035 destoffset = decode_rmXX_address(mod, rl);
2036 DECODE_PRINTF(",");
2037 srcreg = decode_rm_seg_register(rh);
2038 DECODE_PRINTF("\n");
2039 TRACE_AND_STEP();
2040 destval = *srcreg;
2041 store_data_word(destoffset, destval);
2042 } else { /* register to register */
2043 destreg = DECODE_RM_WORD_REGISTER(rl);
2044 DECODE_PRINTF(",");
2045 srcreg = decode_rm_seg_register(rh);
2046 DECODE_PRINTF("\n");
2047 TRACE_AND_STEP();
2048 *destreg = *srcreg;
2049 }
2050 DECODE_CLEAR_SEGOVR();
2051 END_OF_INSTR();
2052}
2053
2054/****************************************************************************
2055REMARKS:
2056Handles opcode 0x8d
2057****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002058static void x86emuOp_lea_word_R_M(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002059{
2060 int mod, rl, rh;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002061 uint destoffset;
2062
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002063 START_OF_INSTR();
2064 DECODE_PRINTF("LEA\t");
2065 FETCH_DECODE_MODRM(mod, rh, rl);
2066 if (mod < 3) {
Stefan Reinauerbbf24962012-07-26 15:40:06 -07002067 if (M.x86.mode & SYSMODE_PREFIX_ADDR) {
2068 u32 *srcreg = DECODE_RM_LONG_REGISTER(rh);
2069 DECODE_PRINTF(",");
2070 destoffset = decode_rmXX_address(mod, rl);
2071 DECODE_PRINTF("\n");
2072 TRACE_AND_STEP();
2073 *srcreg = (u32)destoffset;
2074 } else {
2075 u16 *srcreg = DECODE_RM_WORD_REGISTER(rh);
2076 DECODE_PRINTF(",");
2077 destoffset = decode_rmXX_address(mod, rl);
2078 DECODE_PRINTF("\n");
2079 TRACE_AND_STEP();
2080 *srcreg = (u16)destoffset;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002081 }
Stefan Reinauerbbf24962012-07-26 15:40:06 -07002082 }
2083 /* else { undefined. Do nothing. } */
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002084 DECODE_CLEAR_SEGOVR();
2085 END_OF_INSTR();
2086}
2087
2088/****************************************************************************
2089REMARKS:
2090Handles opcode 0x8e
2091****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002092static void x86emuOp_mov_word_SR_RM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002093{
2094 int mod, rl, rh;
2095 u16 *destreg, *srcreg;
2096 uint srcoffset;
2097 u16 srcval;
2098
2099 START_OF_INSTR();
2100 DECODE_PRINTF("MOV\t");
2101 FETCH_DECODE_MODRM(mod, rh, rl);
2102 if (mod < 3) {
2103 destreg = decode_rm_seg_register(rh);
2104 DECODE_PRINTF(",");
2105 srcoffset = decode_rmXX_address(mod, rl);
2106 srcval = fetch_data_word(srcoffset);
2107 DECODE_PRINTF("\n");
2108 TRACE_AND_STEP();
2109 *destreg = srcval;
2110 } else { /* register to register */
2111 destreg = decode_rm_seg_register(rh);
2112 DECODE_PRINTF(",");
2113 srcreg = DECODE_RM_WORD_REGISTER(rl);
2114 DECODE_PRINTF("\n");
2115 TRACE_AND_STEP();
2116 *destreg = *srcreg;
2117 }
2118 /*
2119 * Clean up, and reset all the R_xSP pointers to the correct
2120 * locations. This is about 3x too much overhead (doing all the
2121 * segreg ptrs when only one is needed, but this instruction
2122 * *cannot* be that common, and this isn't too much work anyway.
2123 */
2124 DECODE_CLEAR_SEGOVR();
2125 END_OF_INSTR();
2126}
2127
2128/****************************************************************************
2129REMARKS:
2130Handles opcode 0x8f
2131****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002132static void x86emuOp_pop_RM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002133{
2134 int mod, rl, rh;
2135 uint destoffset;
2136
2137 START_OF_INSTR();
2138 DECODE_PRINTF("POP\t");
2139 FETCH_DECODE_MODRM(mod, rh, rl);
2140 if (rh != 0) {
2141 DECODE_PRINTF("ILLEGAL DECODE OF OPCODE 8F\n");
2142 HALT_SYS();
2143 }
2144 if (mod < 3) {
2145 destoffset = decode_rmXX_address(mod, rl);
2146 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2147 u32 destval;
2148
2149 DECODE_PRINTF("\n");
2150 TRACE_AND_STEP();
2151 destval = pop_long();
2152 store_data_long(destoffset, destval);
2153 } else {
2154 u16 destval;
2155
2156 DECODE_PRINTF("\n");
2157 TRACE_AND_STEP();
2158 destval = pop_word();
2159 store_data_word(destoffset, destval);
2160 }
2161 } else { /* register to register */
2162 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2163 u32 *destreg;
2164
2165 destreg = DECODE_RM_LONG_REGISTER(rl);
2166 DECODE_PRINTF("\n");
2167 TRACE_AND_STEP();
2168 *destreg = pop_long();
2169 } else {
2170 u16 *destreg;
2171
2172 destreg = DECODE_RM_WORD_REGISTER(rl);
2173 DECODE_PRINTF("\n");
2174 TRACE_AND_STEP();
2175 *destreg = pop_word();
2176 }
2177 }
2178 DECODE_CLEAR_SEGOVR();
2179 END_OF_INSTR();
2180}
2181
2182/****************************************************************************
2183REMARKS:
2184Handles opcode 0x90
2185****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002186static void x86emuOp_nop(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002187{
2188 START_OF_INSTR();
2189 DECODE_PRINTF("NOP\n");
2190 TRACE_AND_STEP();
2191 DECODE_CLEAR_SEGOVR();
2192 END_OF_INSTR();
2193}
2194
2195/****************************************************************************
2196REMARKS:
2197Handles opcode 0x91-0x97
2198****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002199static void x86emuOp_xchg_word_AX_register(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002200{
2201 u32 tmp;
2202
2203 op1 &= 0x7;
2204
2205 START_OF_INSTR();
2206
2207 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2208 u32 *reg32;
2209 DECODE_PRINTF("XCHG\tEAX,");
2210 reg32 = DECODE_RM_LONG_REGISTER(op1);
2211 DECODE_PRINTF("\n");
2212 TRACE_AND_STEP();
2213 tmp = M.x86.R_EAX;
2214 M.x86.R_EAX = *reg32;
2215 *reg32 = tmp;
2216 } else {
2217 u16 *reg16;
2218 DECODE_PRINTF("XCHG\tAX,");
2219 reg16 = DECODE_RM_WORD_REGISTER(op1);
2220 DECODE_PRINTF("\n");
2221 TRACE_AND_STEP();
2222 tmp = M.x86.R_AX;
2223 M.x86.R_AX = *reg16;
2224 *reg16 = (u16)tmp;
2225 }
2226 DECODE_CLEAR_SEGOVR();
2227 END_OF_INSTR();
2228}
2229
2230/****************************************************************************
2231REMARKS:
2232Handles opcode 0x98
2233****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002234static void x86emuOp_cbw(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002235{
2236 START_OF_INSTR();
2237 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2238 DECODE_PRINTF("CWDE\n");
2239 } else {
2240 DECODE_PRINTF("CBW\n");
2241 }
2242 TRACE_AND_STEP();
2243 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2244 if (M.x86.R_AX & 0x8000) {
2245 M.x86.R_EAX |= 0xffff0000;
2246 } else {
2247 M.x86.R_EAX &= 0x0000ffff;
2248 }
2249 } else {
2250 if (M.x86.R_AL & 0x80) {
2251 M.x86.R_AH = 0xff;
2252 } else {
2253 M.x86.R_AH = 0x0;
2254 }
2255 }
2256 DECODE_CLEAR_SEGOVR();
2257 END_OF_INSTR();
2258}
2259
2260/****************************************************************************
2261REMARKS:
2262Handles opcode 0x99
2263****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002264static void x86emuOp_cwd(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002265{
2266 START_OF_INSTR();
2267 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2268 DECODE_PRINTF("CDQ\n");
2269 } else {
2270 DECODE_PRINTF("CWD\n");
2271 }
2272 DECODE_PRINTF("CWD\n");
2273 TRACE_AND_STEP();
2274 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2275 if (M.x86.R_EAX & 0x80000000) {
2276 M.x86.R_EDX = 0xffffffff;
2277 } else {
2278 M.x86.R_EDX = 0x0;
2279 }
2280 } else {
2281 if (M.x86.R_AX & 0x8000) {
2282 M.x86.R_DX = 0xffff;
2283 } else {
2284 M.x86.R_DX = 0x0;
2285 }
2286 }
2287 DECODE_CLEAR_SEGOVR();
2288 END_OF_INSTR();
2289}
2290
2291/****************************************************************************
2292REMARKS:
2293Handles opcode 0x9a
2294****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002295static void x86emuOp_call_far_IMM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002296{
Stefan Reinauer3b695782012-07-26 16:25:53 -07002297 u32 farseg, faroff;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002298
2299 START_OF_INSTR();
Stefan Reinauer3b695782012-07-26 16:25:53 -07002300 DECODE_PRINTF("CALL\t");
2301 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2302 faroff = fetch_long_imm();
2303 farseg = fetch_word_imm();
2304 } else {
2305 faroff = fetch_word_imm();
2306 farseg = fetch_word_imm();
2307 }
2308 DECODE_PRINTF2("%04x:", farseg);
2309 DECODE_PRINTF2("%04x\n", faroff);
2310 CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, farseg, faroff, "FAR ");
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002311
2312 /* XXX
2313 *
2314 * Hooked interrupt vectors calling into our "BIOS" will cause
2315 * problems unless all intersegment stuff is checked for BIOS
2316 * access. Check needed here. For moment, let it alone.
2317 */
2318 TRACE_AND_STEP();
2319 push_word(M.x86.R_CS);
2320 M.x86.R_CS = farseg;
Stefan Reinauer3b695782012-07-26 16:25:53 -07002321 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2322 push_long(M.x86.R_EIP);
2323 } else {
2324 push_word(M.x86.R_IP);
2325 }
2326 M.x86.R_EIP = faroff & 0xffff;
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002327 DECODE_CLEAR_SEGOVR();
2328 END_OF_INSTR();
2329}
2330
2331/****************************************************************************
2332REMARKS:
2333Handles opcode 0x9b
2334****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002335static void x86emuOp_wait(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002336{
2337 START_OF_INSTR();
2338 DECODE_PRINTF("WAIT");
2339 TRACE_AND_STEP();
2340 /* NADA. */
2341 DECODE_CLEAR_SEGOVR();
2342 END_OF_INSTR();
2343}
2344
2345/****************************************************************************
2346REMARKS:
2347Handles opcode 0x9c
2348****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002349static void x86emuOp_pushf_word(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002350{
2351 u32 flags;
2352
2353 START_OF_INSTR();
2354 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2355 DECODE_PRINTF("PUSHFD\n");
2356 } else {
2357 DECODE_PRINTF("PUSHF\n");
2358 }
2359 TRACE_AND_STEP();
2360
2361 /* clear out *all* bits not representing flags, and turn on real bits */
2362 flags = (M.x86.R_EFLG & F_MSK) | F_ALWAYS_ON;
2363 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2364 push_long(flags);
2365 } else {
2366 push_word((u16)flags);
2367 }
2368 DECODE_CLEAR_SEGOVR();
2369 END_OF_INSTR();
2370}
2371
2372/****************************************************************************
2373REMARKS:
2374Handles opcode 0x9d
2375****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002376static void x86emuOp_popf_word(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002377{
2378 START_OF_INSTR();
2379 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2380 DECODE_PRINTF("POPFD\n");
2381 } else {
2382 DECODE_PRINTF("POPF\n");
2383 }
2384 TRACE_AND_STEP();
2385 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2386 M.x86.R_EFLG = pop_long();
2387 } else {
2388 M.x86.R_FLG = pop_word();
2389 }
2390 DECODE_CLEAR_SEGOVR();
2391 END_OF_INSTR();
2392}
2393
2394/****************************************************************************
2395REMARKS:
2396Handles opcode 0x9e
2397****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002398static void x86emuOp_sahf(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002399{
2400 START_OF_INSTR();
2401 DECODE_PRINTF("SAHF\n");
2402 TRACE_AND_STEP();
2403 /* clear the lower bits of the flag register */
2404 M.x86.R_FLG &= 0xffffff00;
2405 /* or in the AH register into the flags register */
2406 M.x86.R_FLG |= M.x86.R_AH;
2407 DECODE_CLEAR_SEGOVR();
2408 END_OF_INSTR();
2409}
2410
2411/****************************************************************************
2412REMARKS:
2413Handles opcode 0x9f
2414****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002415static void x86emuOp_lahf(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002416{
2417 START_OF_INSTR();
2418 DECODE_PRINTF("LAHF\n");
2419 TRACE_AND_STEP();
2420 M.x86.R_AH = (u8)(M.x86.R_FLG & 0xff);
2421 /*undocumented TC++ behavior??? Nope. It's documented, but
2422 you have too look real hard to notice it. */
2423 M.x86.R_AH |= 0x2;
2424 DECODE_CLEAR_SEGOVR();
2425 END_OF_INSTR();
2426}
2427
2428/****************************************************************************
2429REMARKS:
2430Handles opcode 0xa0
2431****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002432static void x86emuOp_mov_AL_M_IMM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002433{
2434 u16 offset;
2435
2436 START_OF_INSTR();
2437 DECODE_PRINTF("MOV\tAL,");
2438 offset = fetch_word_imm();
2439 DECODE_PRINTF2("[%04x]\n", offset);
2440 TRACE_AND_STEP();
2441 M.x86.R_AL = fetch_data_byte(offset);
2442 DECODE_CLEAR_SEGOVR();
2443 END_OF_INSTR();
2444}
2445
2446/****************************************************************************
2447REMARKS:
2448Handles opcode 0xa1
2449****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002450static void x86emuOp_mov_AX_M_IMM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002451{
2452 u16 offset;
2453
2454 START_OF_INSTR();
2455 offset = fetch_word_imm();
2456 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2457 DECODE_PRINTF2("MOV\tEAX,[%04x]\n", offset);
2458 } else {
2459 DECODE_PRINTF2("MOV\tAX,[%04x]\n", offset);
2460 }
2461 TRACE_AND_STEP();
2462 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2463 M.x86.R_EAX = fetch_data_long(offset);
2464 } else {
2465 M.x86.R_AX = fetch_data_word(offset);
2466 }
2467 DECODE_CLEAR_SEGOVR();
2468 END_OF_INSTR();
2469}
2470
2471/****************************************************************************
2472REMARKS:
2473Handles opcode 0xa2
2474****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002475static void x86emuOp_mov_M_AL_IMM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002476{
2477 u16 offset;
2478
2479 START_OF_INSTR();
2480 DECODE_PRINTF("MOV\t");
2481 offset = fetch_word_imm();
2482 DECODE_PRINTF2("[%04x],AL\n", offset);
2483 TRACE_AND_STEP();
2484 store_data_byte(offset, M.x86.R_AL);
2485 DECODE_CLEAR_SEGOVR();
2486 END_OF_INSTR();
2487}
2488
2489/****************************************************************************
2490REMARKS:
2491Handles opcode 0xa3
2492****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002493static void x86emuOp_mov_M_AX_IMM(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002494{
2495 u16 offset;
2496
2497 START_OF_INSTR();
2498 offset = fetch_word_imm();
2499 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2500 DECODE_PRINTF2("MOV\t[%04x],EAX\n", offset);
2501 } else {
2502 DECODE_PRINTF2("MOV\t[%04x],AX\n", offset);
2503 }
2504 TRACE_AND_STEP();
2505 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2506 store_data_long(offset, M.x86.R_EAX);
2507 } else {
2508 store_data_word(offset, M.x86.R_AX);
2509 }
2510 DECODE_CLEAR_SEGOVR();
2511 END_OF_INSTR();
2512}
2513
2514/****************************************************************************
2515REMARKS:
2516Handles opcode 0xa4
2517****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002518static void x86emuOp_movs_byte(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002519{
2520 u8 val;
2521 u32 count;
2522 int inc;
2523
2524 START_OF_INSTR();
2525 DECODE_PRINTF("MOVS\tBYTE\n");
2526 if (ACCESS_FLAG(F_DF)) /* down */
2527 inc = -1;
2528 else
2529 inc = 1;
2530 TRACE_AND_STEP();
2531 count = 1;
2532 if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
Martin Roth63373ed2013-07-08 16:24:19 -06002533 /* don't care whether REPE or REPNE */
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002534 /* move them until (E)CX is ZERO. */
2535 count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX;
2536 M.x86.R_CX = 0;
2537 if (M.x86.mode & SYSMODE_32BIT_REP)
2538 M.x86.R_ECX = 0;
2539 M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
2540 }
2541 while (count--) {
2542 val = fetch_data_byte(M.x86.R_SI);
2543 store_data_byte_abs(M.x86.R_ES, M.x86.R_DI, val);
2544 M.x86.R_SI += inc;
2545 M.x86.R_DI += inc;
2546 if (M.x86.intr & INTR_HALTED)
2547 break;
2548 }
2549 DECODE_CLEAR_SEGOVR();
2550 END_OF_INSTR();
2551}
2552
2553/****************************************************************************
2554REMARKS:
2555Handles opcode 0xa5
2556****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002557static void x86emuOp_movs_word(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002558{
2559 u32 val;
2560 int inc;
2561 u32 count;
2562
2563 START_OF_INSTR();
2564 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2565 DECODE_PRINTF("MOVS\tDWORD\n");
2566 if (ACCESS_FLAG(F_DF)) /* down */
2567 inc = -4;
2568 else
2569 inc = 4;
2570 } else {
2571 DECODE_PRINTF("MOVS\tWORD\n");
2572 if (ACCESS_FLAG(F_DF)) /* down */
2573 inc = -2;
2574 else
2575 inc = 2;
2576 }
2577 TRACE_AND_STEP();
2578 count = 1;
2579 if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
Martin Roth63373ed2013-07-08 16:24:19 -06002580 /* don't care whether REPE or REPNE */
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002581 /* move them until (E)CX is ZERO. */
2582 count = (M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX;
2583 M.x86.R_CX = 0;
2584 if (M.x86.mode & SYSMODE_32BIT_REP)
2585 M.x86.R_ECX = 0;
2586 M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
2587 }
2588 while (count--) {
2589 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2590 val = fetch_data_long(M.x86.R_SI);
2591 store_data_long_abs(M.x86.R_ES, M.x86.R_DI, val);
2592 } else {
2593 val = fetch_data_word(M.x86.R_SI);
2594 store_data_word_abs(M.x86.R_ES, M.x86.R_DI, (u16)val);
2595 }
2596 M.x86.R_SI += inc;
2597 M.x86.R_DI += inc;
2598 if (M.x86.intr & INTR_HALTED)
2599 break;
2600 }
2601 DECODE_CLEAR_SEGOVR();
2602 END_OF_INSTR();
2603}
2604
2605/****************************************************************************
2606REMARKS:
2607Handles opcode 0xa6
2608****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002609static void x86emuOp_cmps_byte(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002610{
2611 s8 val1, val2;
2612 int inc;
2613
2614 START_OF_INSTR();
2615 DECODE_PRINTF("CMPS\tBYTE\n");
2616 TRACE_AND_STEP();
2617 if (ACCESS_FLAG(F_DF)) /* down */
2618 inc = -1;
2619 else
2620 inc = 1;
2621
2622 if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
2623 /* REPE */
2624 /* move them until (E)CX is ZERO. */
2625 while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) {
2626 val1 = fetch_data_byte(M.x86.R_SI);
2627 val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
2628 cmp_byte(val1, val2);
2629 if (M.x86.mode & SYSMODE_32BIT_REP)
2630 M.x86.R_ECX -= 1;
2631 else
2632 M.x86.R_CX -= 1;
2633 M.x86.R_SI += inc;
2634 M.x86.R_DI += inc;
2635 if ( (M.x86.mode & SYSMODE_PREFIX_REPE) && (ACCESS_FLAG(F_ZF) == 0) ) break;
2636 if ( (M.x86.mode & SYSMODE_PREFIX_REPNE) && ACCESS_FLAG(F_ZF) ) break;
2637 if (M.x86.intr & INTR_HALTED)
2638 break;
2639 }
2640 M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
2641 } else {
2642 val1 = fetch_data_byte(M.x86.R_SI);
2643 val2 = fetch_data_byte_abs(M.x86.R_ES, M.x86.R_DI);
2644 cmp_byte(val1, val2);
2645 M.x86.R_SI += inc;
2646 M.x86.R_DI += inc;
2647 }
2648 DECODE_CLEAR_SEGOVR();
2649 END_OF_INSTR();
2650}
2651
2652/****************************************************************************
2653REMARKS:
2654Handles opcode 0xa7
2655****************************************************************************/
Stefan Reinauer7110d402009-11-03 14:59:43 +00002656static void x86emuOp_cmps_word(u8 X86EMU_UNUSED(op1))
Stefan Reinauer38cd29e2009-08-11 21:28:25 +00002657{
2658 u32 val1,val2;
2659 int inc;
2660
2661 START_OF_INSTR();
2662 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2663 DECODE_PRINTF("CMPS\tDWORD\n");
2664 inc = 4;
2665 } else {
2666 DECODE_PRINTF("CMPS\tWORD\n");
2667 inc = 2;
2668 }
2669 if (ACCESS_FLAG(F_DF)) /* down */
2670 inc = -inc;
2671
2672 TRACE_AND_STEP();
2673 if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
2674 /* REPE */
2675 /* move them until (E)CX is ZERO. */
2676 while (((M.x86.mode & SYSMODE_32BIT_REP) ? M.x86.R_ECX : M.x86.R_CX) != 0) {
2677 if (M.x86.mode & SYSMODE_PREFIX_DATA) {
2678 val1 = fetch_data_long(M.x86.R_SI);
2679