/* | |
* Dos/PC Emulator | |
* Copyright (C) 1991 Jim Hudgens | |
* | |
* | |
* The file is part of GDE. | |
* | |
* GDE is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License as published by | |
* the Free Software Foundation; either version 1, or (at your option) | |
* any later version. | |
* | |
* GDE is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
* | |
* You should have received a copy of the GNU General Public License | |
* along with GDE; see the file COPYING. If not, write to | |
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
* | |
*/ | |
#include "altairz80_defs.h" | |
#include "i86.h" | |
extern void out(const uint32 Port, const uint32 Value); | |
extern uint32 in(const uint32 Port); | |
/* $Log: i86_ops.c,v $ | |
* Revision 0.11 1991/07/30 02:02:04 hudgens | |
* added copyright. | |
* | |
* Revision 0.10 1991/07/21 18:22:08 hudgens | |
* Fixed problem with scans, which was the result of the loop break | |
* condition being incorrect when used in conjunction with the repe | |
* or repne prefixes. Eureka. pkzip/pkunzip now compress/decompress | |
* correctly. | |
* | |
* Revision 0.9 1991/07/21 03:33:18 hudgens | |
* fixed popf so that it appears to be the same as an 8088 popf, and always | |
* sets the high 4 bits of the flags. | |
* | |
* Revision 0.8 1991/07/21 01:44:11 hudgens | |
* fixed aad and aam instructions. | |
* | |
* Revision 0.7 1991/07/21 00:31:24 hudgens | |
* Fixed iret so that it works correctly. | |
* | |
* Revision 0.6 1991/07/20 16:54:50 hudgens | |
* removed the 8087 coprocessor operations. Moved to i87_ops.c | |
* | |
* Revision 0.5 1991/07/17 03:50:10 hudgens | |
* Minor modifications. | |
* | |
* Revision 0.4 1991/06/18 02:48:41 hudgens | |
* Fixed a problem with scasb and scasw. | |
* | |
* Revision 0.3 1991/06/03 01:01:10 hudgens | |
* fixed minor problems due to unsigned to signed short integer | |
* promotions. | |
* | |
* Revision 0.2 1991/03/31 01:32:10 hudgens | |
* fixed segment handling. Added calls to DECODE_CLEAR_SEGOVR in | |
* many places in the code. Should work much better now. | |
* | |
* Revision 0.1 1991/03/30 21:15:48 hudgens | |
* Initial checkin to RCS. | |
* | |
* | |
*/ | |
/* 2/23/91 fixed decode for operand x87. */ | |
/* partially mechanically generated file....(based on the optable) */ | |
/* | |
There are approximately 250 subroutines in here, which correspond | |
to the 256 byte-"opcodes" found on the 8086. The table which | |
dispatches this is found in the files optab.[ch]. | |
Each opcode proc has a comment preceeding it which gives it's table | |
address. Several opcodes are missing (undefined) in the table. | |
Each proc includes information for decoding (DECODE_PRINTF and | |
and misc functions ( | |
Many of the procedures are *VERY* similar in coding. This has | |
allowed for a very large amount of code to be generated in a fairly | |
short amount of time (i.e. cut, paste, and modify). | |
The result is that much of the code below could | |
have been folded into subroutines for a large reduction in size of | |
this file. The downside would be that there would be a penalty in | |
execution speed. The file could also have been *MUCH* larger by | |
inlining certain functions which were called. This could have | |
resulted even faster execution. The prime directive I used to decide | |
whether to inline the code or to modularize it, was basically: 1) no | |
unnecessary subroutine calls, 2) no routines more than about 200 lines | |
in size, and 3) modularize any code that I might not get right the first | |
time. The fetch_* subroutines fall into the latter category. The | |
The decode_* fall into the second category. The coding of the | |
"switch(mod){ .... }" in many of the subroutines below falls into the | |
first category. Especially, the coding of {add,and,or,sub,...}_{byte,word} | |
subroutines are an especially glaring case of the third guideline. | |
Since so much of the code is cloned from other modules (compare | |
opcode #00 to opcode #01), making the basic operations subroutine calls | |
is especially important; otherwise mistakes in coding an "add" | |
would represent a nightmare in maintenance. | |
So, without further ado, ... | |
*/ | |
extern uint8 parity_tab[]; | |
static void i86op_illegal_op(PC_ENV *m) | |
{ | |
intr |= INTR_ILLEGAL_OPCODE; | |
} | |
/*opcode=0x00*/ | |
static void i86op_add_byte_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 destoffset; | |
uint8 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = add_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = add_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = add_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
*destreg = add_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x01*/ | |
static void i86op_add_word_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 destoffset; | |
uint16 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = add_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = add_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = add_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
*destreg = add_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x02*/ | |
static void i86op_add_byte_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint8 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = add_byte(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = add_byte(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = add_byte(m, * destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
*destreg = add_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x03*/ | |
static void i86op_add_word_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint16 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = add_word(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = add_word(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = add_word(m, *destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rl); | |
*destreg = add_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x04*/ | |
static void i86op_add_byte_AL_IMM(PC_ENV *m) | |
{ | |
uint8 srcval; | |
srcval = fetch_byte_imm(m); | |
m->R_AL = add_byte(m, m->R_AL, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x05*/ | |
static void i86op_add_word_AX_IMM(PC_ENV *m) | |
{ | |
uint16 srcval; | |
srcval = fetch_word_imm(m); | |
m->R_AX = add_word(m, m->R_AX, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x06*/ | |
static void i86op_push_ES(PC_ENV *m) | |
{ | |
push_word(m,m->R_ES); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x07*/ | |
static void i86op_pop_ES(PC_ENV *m) | |
{ | |
m->R_ES = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x08*/ | |
static void i86op_or_byte_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 destoffset; | |
uint8 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = or_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = or_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = or_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
*destreg = or_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x09*/ | |
static void i86op_or_word_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 destoffset; | |
uint16 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = or_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = or_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = or_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
*destreg = or_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x0a*/ | |
static void i86op_or_byte_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint8 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = or_byte(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = or_byte(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = or_byte(m, * destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
*destreg = or_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x0b*/ | |
static void i86op_or_word_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint16 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = or_word(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = or_word(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = or_word(m, *destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rl); | |
*destreg = or_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x0c*/ | |
static void i86op_or_byte_AL_IMM(PC_ENV *m) | |
{ | |
uint8 srcval; | |
srcval = fetch_byte_imm(m); | |
m->R_AL = or_byte(m, m->R_AL, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x0d*/ | |
static void i86op_or_word_AX_IMM(PC_ENV *m) | |
{ | |
uint16 srcval; | |
srcval = fetch_word_imm(m); | |
m->R_AX = or_word(m, m->R_AX, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x0e*/ | |
static void i86op_push_CS(PC_ENV *m) | |
{ | |
push_word(m,m->R_CS); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x0f === ILLEGAL OP*/ | |
/*opcode=0x10*/ | |
static void i86op_adc_byte_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 destoffset; | |
uint8 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = adc_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = adc_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = adc_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
*destreg = adc_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x11*/ | |
static void i86op_adc_word_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 destoffset; | |
uint16 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = adc_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = adc_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = adc_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
*destreg = adc_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x12*/ | |
static void i86op_adc_byte_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint8 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = adc_byte(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = adc_byte(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = adc_byte(m, * destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
*destreg = adc_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x13*/ | |
static void i86op_adc_word_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint16 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = adc_word(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = adc_word(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = adc_word(m, *destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rl); | |
*destreg = adc_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x14*/ | |
static void i86op_adc_byte_AL_IMM(PC_ENV *m) | |
{ | |
uint8 srcval; | |
srcval = fetch_byte_imm(m); | |
m->R_AL = adc_byte(m, m->R_AL, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x15*/ | |
static void i86op_adc_word_AX_IMM(PC_ENV *m) | |
{ | |
uint16 srcval; | |
srcval = fetch_word_imm(m); | |
m->R_AX = adc_word(m, m->R_AX, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x16*/ | |
static void i86op_push_SS(PC_ENV *m) | |
{ | |
push_word(m,m->R_SS); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x17*/ | |
static void i86op_pop_SS(PC_ENV *m) | |
{ | |
m->R_SS = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x18*/ | |
static void i86op_sbb_byte_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 destoffset; | |
uint8 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = sbb_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = sbb_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = sbb_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
*destreg = sbb_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x19*/ | |
static void i86op_sbb_word_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 destoffset; | |
uint16 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = sbb_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = sbb_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = sbb_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
*destreg = sbb_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x1a*/ | |
static void i86op_sbb_byte_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint8 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = sbb_byte(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = sbb_byte(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = sbb_byte(m, * destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
*destreg = sbb_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x1b*/ | |
static void i86op_sbb_word_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint16 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = sbb_word(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = sbb_word(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = sbb_word(m, *destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rl); | |
*destreg = sbb_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x1c*/ | |
static void i86op_sbb_byte_AL_IMM(PC_ENV *m) | |
{ | |
uint8 srcval; | |
srcval = fetch_byte_imm(m); | |
m->R_AL = sbb_byte(m, m->R_AL, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x1d*/ | |
static void i86op_sbb_word_AX_IMM(PC_ENV *m) | |
{ | |
uint16 srcval; | |
srcval = fetch_word_imm(m); | |
m->R_AX = sbb_word(m, m->R_AX, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x1e*/ | |
static void i86op_push_DS(PC_ENV *m) | |
{ | |
push_word(m,m->R_DS); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x1f*/ | |
static void i86op_pop_DS(PC_ENV *m) | |
{ | |
m->R_DS = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x20*/ | |
static void i86op_and_byte_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 destoffset; | |
uint8 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = and_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = and_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = and_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
*destreg = and_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x21*/ | |
static void i86op_and_word_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 destoffset; | |
uint16 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = and_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = and_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = and_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
*destreg = and_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x22*/ | |
static void i86op_and_byte_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint8 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = and_byte(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = and_byte(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = and_byte(m, * destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
*destreg = and_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x23*/ | |
static void i86op_and_word_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint16 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = and_word(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = and_word(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = and_word(m, *destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rl); | |
*destreg = and_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x24*/ | |
static void i86op_and_byte_AL_IMM(PC_ENV *m) | |
{ | |
uint8 srcval; | |
srcval = fetch_byte_imm(m); | |
m->R_AL = and_byte(m, m->R_AL, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x25*/ | |
static void i86op_and_word_AX_IMM(PC_ENV *m) | |
{ | |
uint16 srcval; | |
srcval = fetch_word_imm(m); | |
m->R_AX = and_word(m, m->R_AX, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x26*/ | |
static void i86op_segovr_ES(PC_ENV *m) | |
{ | |
m->sysmode |= SYSMODE_SEGOVR_ES; | |
/* note the lack of DECODE_CLEAR_SEGOVR(r) | |
since, here is one of 4 opcode subroutines we do not | |
want to do this. | |
*/ | |
} | |
/*opcode=0x27*/ | |
static void i86op_daa(PC_ENV *m) | |
{ | |
uint16 dbyte; | |
dbyte = m->R_AL; | |
if (ACCESS_FLAG(m,F_AF)|| (dbyte&0xf) > 9) | |
{ | |
dbyte += 6; | |
if (dbyte&0x100) | |
SET_FLAG(m, F_CF); | |
SET_FLAG(m, F_AF); | |
} | |
else | |
CLEAR_FLAG(m, F_AF); | |
if (ACCESS_FLAG(m,F_CF) || (dbyte&0xf0) > 0x90) | |
{ | |
dbyte += 0x60; | |
SET_FLAG(m, F_CF); | |
} | |
else | |
CLEAR_FLAG(m, F_CF); | |
m->R_AL = (uint8) dbyte; | |
CONDITIONAL_SET_FLAG((m->R_AL & 0x80),m,F_SF); | |
CONDITIONAL_SET_FLAG((m->R_AL == 0), m,F_ZF); | |
CONDITIONAL_SET_FLAG((parity_tab[m->R_AL]),m,F_PF); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x28*/ | |
static void i86op_sub_byte_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 destoffset; | |
uint8 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = sub_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = sub_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = sub_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
*destreg = sub_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x29*/ | |
static void i86op_sub_word_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 destoffset; | |
uint16 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = sub_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = sub_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = sub_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
*destreg = sub_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x2a*/ | |
static void i86op_sub_byte_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint8 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = sub_byte(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = sub_byte(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = sub_byte(m, * destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
*destreg = sub_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x2b*/ | |
static void i86op_sub_word_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint16 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = sub_word(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = sub_word(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = sub_word(m, *destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rl); | |
*destreg = sub_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x2c*/ | |
static void i86op_sub_byte_AL_IMM(PC_ENV *m) | |
{ | |
uint8 srcval; | |
srcval = fetch_byte_imm(m); | |
m->R_AL = sub_byte(m, m->R_AL, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x2d*/ | |
static void i86op_sub_word_AX_IMM(PC_ENV *m) | |
{ | |
uint16 srcval; | |
srcval = fetch_word_imm(m); | |
m->R_AX = sub_word(m, m->R_AX, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x2e*/ | |
static void i86op_segovr_CS(PC_ENV *m) | |
{ | |
m->sysmode |= SYSMODE_SEGOVR_CS; | |
/* note no DECODE_CLEAR_SEGOVER here. */ | |
} | |
/*opcode=0x2f*/ | |
static void i86op_das(PC_ENV *m) | |
{ | |
uint16 dbyte; | |
dbyte = m->R_AL; | |
if ( ACCESS_FLAG(m,F_AF) || (dbyte&0xf) > 9) | |
{ | |
dbyte -= 6; | |
if (dbyte&0x100) /* XXXXX --- this is WRONG */ | |
SET_FLAG(m, F_CF); | |
SET_FLAG(m, F_AF); | |
} | |
else | |
CLEAR_FLAG(m, F_AF); | |
if (ACCESS_FLAG(m,F_CF) || (dbyte&0xf0) > 0x90) | |
{ | |
dbyte -= 0x60; | |
SET_FLAG(m, F_CF); | |
} | |
else | |
CLEAR_FLAG(m, F_CF); | |
m->R_AL = (uint8) dbyte; | |
CONDITIONAL_SET_FLAG(m->R_AL & 0x80,m,F_SF); | |
CONDITIONAL_SET_FLAG(m->R_AL == 0,m,F_ZF); | |
CONDITIONAL_SET_FLAG(parity_tab[m->R_AL],m,F_PF); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x30*/ | |
static void i86op_xor_byte_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 destoffset; | |
uint8 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = xor_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = xor_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
destval = xor_byte(m, destval, *srcreg); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
*destreg = xor_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x31*/ | |
static void i86op_xor_word_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 destoffset; | |
uint16 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = xor_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = xor_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destval = xor_word(m, destval, *srcreg); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
*destreg = xor_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x32*/ | |
static void i86op_xor_byte_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint8 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = xor_byte(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = xor_byte(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = xor_byte(m, *destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
*destreg = xor_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x33*/ | |
static void i86op_xor_word_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint16 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = xor_word(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = xor_word(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = xor_word(m, *destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rl); | |
*destreg = xor_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x34*/ | |
static void i86op_xor_byte_AL_IMM(PC_ENV *m) | |
{ | |
uint8 srcval; | |
srcval = fetch_byte_imm(m); | |
m->R_AL = xor_byte(m, m->R_AL, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x35*/ | |
static void i86op_xor_word_AX_IMM(PC_ENV *m) | |
{ | |
uint16 srcval; | |
srcval = fetch_word_imm(m); | |
m->R_AX = xor_word(m, m->R_AX, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x36*/ | |
static void i86op_segovr_SS(PC_ENV *m) | |
{ | |
m->sysmode |= SYSMODE_SEGOVR_SS; | |
/* no DECODE_CLEAR_SEGOVER ! */ | |
} | |
/*opcode=0x37*/ | |
static void i86op_aaa(PC_ENV *m) | |
{ | |
if ( (m->R_AL & 0xf) > 0x9 || ACCESS_FLAG(m,F_AF)) | |
{ | |
m->R_AL += 0x6; | |
m->R_AH += 1; | |
SET_FLAG(m, F_AF); | |
SET_FLAG(m, F_CF); | |
} | |
else | |
{ | |
CLEAR_FLAG(m, F_CF); | |
CLEAR_FLAG(m, F_AF); | |
} | |
m->R_AL &= 0xf; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x38*/ | |
static void i86op_cmp_byte_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 destoffset; | |
uint8 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
cmp_byte(m, destval, *srcreg); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
cmp_byte(m, destval, *srcreg); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
cmp_byte(m, destval, *srcreg); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
cmp_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x39*/ | |
static void i86op_cmp_word_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 destoffset; | |
uint16 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
cmp_word(m, destval, *srcreg); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
cmp_word(m, destval, *srcreg); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
cmp_word(m, destval, *srcreg); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
cmp_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x3a*/ | |
static void i86op_cmp_byte_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint8 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
cmp_byte(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
cmp_byte(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
cmp_byte(m, * destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
cmp_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x3b*/ | |
static void i86op_cmp_word_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint16 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
cmp_word(m, *destreg, srcval); | |
break; | |
case 1: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
cmp_word(m, *destreg, srcval); | |
break; | |
case 2: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
cmp_word(m, *destreg, srcval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rl); | |
cmp_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x3c*/ | |
static void i86op_cmp_byte_AL_IMM(PC_ENV *m) | |
{ | |
uint8 srcval; | |
srcval = fetch_byte_imm(m); | |
cmp_byte(m, m->R_AL, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x3d*/ | |
static void i86op_cmp_word_AX_IMM(PC_ENV *m) | |
{ | |
uint16 srcval; | |
srcval = fetch_word_imm(m); | |
cmp_word(m, m->R_AX, srcval); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x3e*/ | |
static void i86op_segovr_DS(PC_ENV *m) | |
{ | |
m->sysmode |= SYSMODE_SEGOVR_DS; | |
/* NO DECODE_CLEAR_SEGOVR! */ | |
} | |
/*opcode=0x3f*/ | |
static void i86op_aas(PC_ENV *m) | |
{ | |
/* ???? Check out the subtraction here. Will this ?ever? cause | |
the contents of R_AL or R_AH to be affected incorrectly since | |
they are being subtracted from *and* are unsigned. | |
Should put an assertion in here. | |
*/ | |
if ( (m->R_AL & 0xf) > 0x9 || ACCESS_FLAG(m,F_AF)) | |
{ | |
m->R_AL -= 0x6; | |
m->R_AH -= 1; | |
SET_FLAG(m, F_AF); | |
SET_FLAG(m, F_CF); | |
} | |
else | |
{ | |
CLEAR_FLAG(m, F_CF); | |
CLEAR_FLAG(m, F_AF); | |
} | |
m->R_AL &= 0xf; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x40*/ | |
static void i86op_inc_AX(PC_ENV *m) | |
{ | |
m->R_AX = inc_word(m,m->R_AX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x41*/ | |
static void i86op_inc_CX(PC_ENV *m) | |
{ | |
m->R_CX = inc_word(m,m->R_CX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x42*/ | |
static void i86op_inc_DX(PC_ENV *m) | |
{ | |
m->R_DX = inc_word(m,m->R_DX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x43*/ | |
static void i86op_inc_BX(PC_ENV *m) | |
{ | |
m->R_BX = inc_word(m,m->R_BX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x44*/ | |
static void i86op_inc_SP(PC_ENV *m) | |
{ | |
m->R_SP = inc_word(m,m->R_SP); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x45*/ | |
static void i86op_inc_BP(PC_ENV *m) | |
{ | |
m->R_BP = inc_word(m,m->R_BP); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x46*/ | |
static void i86op_inc_SI(PC_ENV *m) | |
{ | |
m->R_SI = inc_word(m,m->R_SI); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x47*/ | |
static void i86op_inc_DI(PC_ENV *m) | |
{ | |
m->R_DI = inc_word(m,m->R_DI); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x48*/ | |
static void i86op_dec_AX(PC_ENV *m) | |
{ | |
m->R_AX = dec_word(m,m->R_AX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x49*/ | |
static void i86op_dec_CX(PC_ENV *m) | |
{ | |
m->R_CX = dec_word(m,m->R_CX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x4a*/ | |
static void i86op_dec_DX(PC_ENV *m) | |
{ | |
m->R_DX = dec_word(m,m->R_DX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x4b*/ | |
static void i86op_dec_BX(PC_ENV *m) | |
{ | |
m->R_BX = dec_word(m,m->R_BX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x4c*/ | |
static void i86op_dec_SP(PC_ENV *m) | |
{ | |
m->R_SP = dec_word(m,m->R_SP); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x4d*/ | |
static void i86op_dec_BP(PC_ENV *m) | |
{ | |
m->R_BP = dec_word(m,m->R_BP); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x4e*/ | |
static void i86op_dec_SI(PC_ENV *m) | |
{ | |
m->R_SI = dec_word(m,m->R_SI); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x4f*/ | |
static void i86op_dec_DI(PC_ENV *m) | |
{ | |
m->R_DI = dec_word(m,m->R_DI); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x50*/ | |
static void i86op_push_AX(PC_ENV *m) | |
{ | |
push_word(m,m->R_AX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x51*/ | |
static void i86op_push_CX(PC_ENV *m) | |
{ | |
push_word(m,m->R_CX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x52*/ | |
static void i86op_push_DX(PC_ENV *m) | |
{ | |
push_word(m,m->R_DX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x53*/ | |
static void i86op_push_BX(PC_ENV *m) | |
{ | |
push_word(m,m->R_BX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x54*/ | |
static void i86op_push_SP(PC_ENV *m) | |
{ | |
/* .... Note this weirdness: One book I have access to | |
claims that the value pushed here is actually sp-2. I.e. | |
it decrements the stackpointer, and then pushes it. The 286 | |
I have does it this way. Changing this causes many problems.*/ | |
/* changed to push SP-2, since this *IS* how a 8088 does this */ | |
push_word(m,m->R_SP-2); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x55*/ | |
static void i86op_push_BP(PC_ENV *m) | |
{ | |
push_word(m,m->R_BP); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x56*/ | |
static void i86op_push_SI(PC_ENV *m) | |
{ | |
push_word(m,m->R_SI); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x57*/ | |
static void i86op_push_DI(PC_ENV *m) | |
{ | |
push_word(m,m->R_DI); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x58*/ | |
static void i86op_pop_AX(PC_ENV *m) | |
{ | |
m->R_AX = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x59*/ | |
static void i86op_pop_CX(PC_ENV *m) | |
{ | |
m->R_CX = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x5a*/ | |
static void i86op_pop_DX(PC_ENV *m) | |
{ | |
m->R_DX = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x5b*/ | |
static void i86op_pop_BX(PC_ENV *m) | |
{ | |
m->R_BX = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x5c*/ | |
static void i86op_pop_SP(PC_ENV *m) | |
{ | |
m->R_SP = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x5d*/ | |
static void i86op_pop_BP(PC_ENV *m) | |
{ | |
m->R_BP = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x5e*/ | |
static void i86op_pop_SI(PC_ENV *m) | |
{ | |
m->R_SI = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x5f*/ | |
static void i86op_pop_DI(PC_ENV *m) | |
{ | |
m->R_DI = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x60 ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x61 ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x62 ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x63 ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x64 ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x65 ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x66 ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x67 ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x68 ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x69 ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x6a ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x6b ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x6c ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x6d ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x6e ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x6f ILLEGAL OP, calls i86op_illegal_op() */ | |
/*opcode=0x70*/ | |
static void i86op_jump_near_O(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
/* jump to byte offset if overflow flag is set */ | |
offset = (int8) fetch_byte_imm(m); | |
target = (int16)(m->R_IP) + offset; | |
if (ACCESS_FLAG(m,F_OF)) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x71*/ | |
static void i86op_jump_near_NO(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
/* jump to byte offset if overflow is not set */ | |
offset = (int8) fetch_byte_imm(m); | |
target = (int16)(m->R_IP) + offset; | |
if (!ACCESS_FLAG(m,F_OF)) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x72*/ | |
static void i86op_jump_near_B(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
/* jump to byte offset if carry flag is set. */ | |
offset = (int8)fetch_byte_imm(m); /* sign extended ??? */ | |
target = (int16)(m->R_IP) + offset; | |
if (ACCESS_FLAG(m, F_CF)) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x73*/ | |
static void i86op_jump_near_NB(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
/* jump to byte offset if carry flag is clear. */ | |
offset = (int8)fetch_byte_imm(m); /* sign extended ??? */ | |
target = (int16)(m->R_IP) + offset; | |
if (!ACCESS_FLAG(m,F_CF)) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x74*/ | |
static void i86op_jump_near_Z(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
/* jump to byte offset if zero flag is set. */ | |
offset = (int8)fetch_byte_imm(m); | |
target = (int16)(m->R_IP) + offset; | |
if (ACCESS_FLAG(m, F_ZF)) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x75*/ | |
static void i86op_jump_near_NZ(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
/* jump to byte offset if zero flag is clear. */ | |
offset = (int8)fetch_byte_imm(m); | |
target = (int16)(m->R_IP) + offset; | |
if (!ACCESS_FLAG(m, F_ZF)) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x76*/ | |
static void i86op_jump_near_BE(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
/* jump to byte offset if carry flag is set or if the zero | |
flag is set. */ | |
offset = (int8)fetch_byte_imm(m); | |
target = (int16)(m->R_IP) + offset; | |
if (ACCESS_FLAG(m,F_CF) || ACCESS_FLAG(m,F_ZF)) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x77*/ | |
static void i86op_jump_near_NBE(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
/* jump to byte offset if carry flag is clear and if the zero | |
flag is clear */ | |
offset = (int8)fetch_byte_imm(m); | |
target = (int16)(m->R_IP) + offset; | |
if (!(ACCESS_FLAG(m,F_CF)||ACCESS_FLAG(m,F_ZF))) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x78*/ | |
static void i86op_jump_near_S(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
/* jump to byte offset if sign flag is set */ | |
offset = (int8)fetch_byte_imm(m); | |
target = (int16)(m->R_IP) + offset; | |
if (ACCESS_FLAG(m,F_SF)) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x79*/ | |
static void i86op_jump_near_NS(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
/* jump to byte offset if sign flag is clear */ | |
offset = (int8)fetch_byte_imm(m); | |
target = (int16)(m->R_IP) + offset; | |
if (!ACCESS_FLAG(m,F_SF)) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x7a*/ | |
static void i86op_jump_near_P(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
/* jump to byte offset if parity flag is set (even parity) */ | |
offset = (int8)fetch_byte_imm(m); | |
target = (int16)(m->R_IP) + offset; | |
if (ACCESS_FLAG(m, F_PF)) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x7b*/ | |
static void i86op_jump_near_NP(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
/* jump to byte offset if parity flag is clear (odd parity) */ | |
offset = (int8)fetch_byte_imm(m); | |
target = (int16)(m->R_IP) + offset; | |
if (!ACCESS_FLAG(m, F_PF)) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* JHH fixed till here... */ | |
/*opcode=0x7c*/ | |
static void i86op_jump_near_L(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
int sf,of; | |
/* jump to byte offset if sign flag not equal to overflow flag. */ | |
offset = (int8)fetch_byte_imm(m); | |
target = (int16)(m->R_IP) + offset; | |
/* note: | |
* this is the simplest expression i could think of which | |
* expresses SF != OF. m->R_FLG&F_SF either equals x80 or x00. | |
* Similarly m->R_FLG&F_OF either equals x800 or x000. | |
* The former shifted right by 7 puts a 1 or 0 in bit 0. | |
* The latter shifter right by 11 puts a 1 or 0 in bit 0. | |
* if the two expressions are the same, i.e. equal, then | |
* a zero results from the xor. If they are not equal, | |
* then a 1 results, and the jump is taken. | |
*/ | |
sf = ACCESS_FLAG(m,F_SF) != 0; | |
of = ACCESS_FLAG(m,F_OF) != 0; | |
/* was: if ( ((m->R_FLG & F_SF)>>7) ^ ((m->R_FLG & F_OF) >> 11))*/ | |
if (sf ^ of) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x7d*/ | |
static void i86op_jump_near_NL(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
int sf,of; | |
/* jump to byte offset if sign flag not equal to overflow flag. */ | |
offset = (int8)fetch_byte_imm(m); | |
target = (int16)(m->R_IP) + offset; | |
sf = ACCESS_FLAG(m,F_SF) != 0; | |
of = ACCESS_FLAG(m,F_OF) != 0; | |
/* note: inverse of above, but using == instead of xor. */ | |
/* was: if (((m->R_FLG & F_SF)>>7) == ((m->R_FLG & F_OF) >> 11))*/ | |
if (sf == of) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x7e*/ | |
static void i86op_jump_near_LE(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
int sf,of; | |
/* jump to byte offset if sign flag not equal to overflow flag | |
or the zero flag is set */ | |
offset = (int8)fetch_byte_imm(m); | |
target = (int16)(m->R_IP) + offset; | |
sf = ACCESS_FLAG(m,F_SF) != 0; | |
of = ACCESS_FLAG(m,F_OF) != 0; | |
/* note: modification of JL */ | |
/* sf != of */ | |
/* was: if ((((m->R_FLG & F_SF)>>7) ^ ((m->R_FLG & F_OF) >> 11)) | |
|| (m->R_FLG & F_ZF) ) */ | |
if ( (sf ^ of) || ACCESS_FLAG(m,F_ZF)) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x7f*/ | |
static void i86op_jump_near_NLE(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
int sf,of; | |
/* jump to byte offset if sign flag equal to overflow flag. | |
and the zero flag is clear*/ | |
offset = (int8)fetch_byte_imm(m); | |
target = (int16)(m->R_IP) + offset; | |
sf = ACCESS_FLAG(m,F_SF) != 0; | |
of = ACCESS_FLAG(m,F_OF) != 0; | |
/* if (((m->R_FLG & F_SF)>>7) == ((m->R_FLG & F_OF) >> 11) | |
&& (!(m->R_FLG & F_ZF))) */ | |
if ( ( sf == of ) && !ACCESS_FLAG(m,F_ZF)) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
static uint8 (*opc80_byte_operation[])(PC_ENV *m,uint8 d,uint8 s) = | |
{ | |
add_byte,/*00*/ | |
or_byte, /*01*/ | |
adc_byte,/*02*/ | |
sbb_byte,/*03*/ | |
and_byte,/*04*/ | |
sub_byte,/*05*/ | |
xor_byte,/*06*/ | |
cmp_byte,/*07*/ | |
}; | |
/*opcode=0x80*/ | |
static void i86op_opc80_byte_RM_IMM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg; | |
uint16 destoffset; | |
uint8 imm; | |
uint8 destval; | |
/* weirdo special case instruction format. Part of the | |
opcode held below in "RH". Doubly nested case would | |
result, except that the decoded instruction | |
*/ | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
/* know operation, decode the mod byte to find the addressing | |
mode. */ | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
imm = fetch_byte_imm(m); | |
destval = (*opc80_byte_operation[rh])(m, destval, imm); | |
if (rh != 7) | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
imm = fetch_byte_imm(m); | |
destval = (*opc80_byte_operation[rh])(m, destval, imm); | |
if (rh != 7) | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
imm = fetch_byte_imm(m); | |
destval = (*opc80_byte_operation[rh])(m, destval, imm); | |
if (rh != 7) | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
imm = fetch_byte_imm(m); | |
destval = (*opc80_byte_operation[rh])(m, *destreg, imm); | |
if (rh != 7) | |
*destreg = destval; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
static uint16 (*opc81_word_operation[])(PC_ENV *m,uint16 d,uint16 s) = | |
{ add_word,/*00*/ | |
or_word, /*01*/ | |
adc_word,/*02*/ | |
sbb_word,/*03*/ | |
and_word,/*04*/ | |
sub_word,/*05*/ | |
xor_word,/*06*/ | |
cmp_word,/*07*/ | |
}; | |
/*opcode=0x81*/ | |
static void i86op_opc81_word_RM_IMM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg; | |
uint16 destoffset; | |
uint16 imm; | |
uint16 destval; | |
/* weirdo special case instruction format. Part of the | |
opcode held below in "RH". Doubly nested case would | |
result, except that the decoded instruction | |
*/ | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
/* know operation, decode the mod byte to find the addressing | |
mode. */ | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
imm = fetch_word_imm(m); | |
destval = (*opc81_word_operation[rh])(m, destval, imm); | |
if (rh != 7) | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
imm = fetch_word_imm(m); | |
destval = (*opc81_word_operation[rh])(m, destval, imm); | |
if (rh != 7) | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
imm = fetch_word_imm(m); | |
destval = (*opc81_word_operation[rh])(m, destval, imm); | |
if (rh != 7) | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
imm = fetch_word_imm(m); | |
destval = (*opc81_word_operation[rh])(m, *destreg, imm); | |
if (rh != 7) | |
*destreg = destval; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
static uint8 (*opc82_byte_operation[])(PC_ENV *m,uint8 s,uint8 d) = | |
{ | |
add_byte,/*00*/ | |
or_byte, /*01*/ /*YYY UNUSED ????*/ | |
adc_byte,/*02*/ | |
sbb_byte,/*03*/ | |
and_byte,/*04*/ /*YYY UNUSED ????*/ | |
sub_byte,/*05*/ | |
xor_byte,/*06*/ /*YYY UNUSED ????*/ | |
cmp_byte,/*07*/ | |
}; | |
/*opcode=0x82*/ | |
static void i86op_opc82_byte_RM_IMM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg; | |
uint16 destoffset; | |
uint8 imm; | |
uint8 destval; | |
/* weirdo special case instruction format. Part of the | |
opcode held below in "RH". Doubly nested case would | |
result, except that the decoded instruction | |
Similar to opcode 81, except that the immediate byte | |
is sign extended to a word length. | |
*/ | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
/* know operation, decode the mod byte to find the addressing | |
mode. */ | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
imm = fetch_byte_imm(m); | |
destval = (*opc82_byte_operation[rh])(m, destval, imm); | |
if (rh != 7) | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
imm = fetch_byte_imm(m); | |
destval = (*opc82_byte_operation[rh])(m, destval, imm); | |
if (rh != 7) | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
imm = fetch_byte_imm(m); | |
destval = (*opc82_byte_operation[rh])(m, destval, imm); | |
if (rh != 7) | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
imm = fetch_byte_imm(m); | |
destval = (*opc82_byte_operation[rh])(m, *destreg, imm); | |
if (rh != 7) | |
*destreg = destval; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
static uint16 (*opc83_word_operation[])(PC_ENV *m,uint16 s,uint16 d) = | |
{ | |
add_word,/*00*/ | |
or_word, /*01*/ /*YYY UNUSED ????*/ | |
adc_word,/*02*/ | |
sbb_word,/*03*/ | |
and_word,/*04*/ /*YYY UNUSED ????*/ | |
sub_word,/*05*/ | |
xor_word,/*06*/ /*YYY UNUSED ????*/ | |
cmp_word,/*07*/ | |
}; | |
/*opcode=0x83*/ | |
static void i86op_opc83_word_RM_IMM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg; | |
uint16 destoffset; | |
uint16 imm; | |
uint16 destval; | |
/* weirdo special case instruction format. Part of the | |
opcode held below in "RH". Doubly nested case would | |
result, except that the decoded instruction | |
Similar to opcode 81, except that the immediate byte | |
is sign extended to a word length. | |
*/ | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
/* know operation, decode the mod byte to find the addressing | |
mode. */ | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
imm = (int8)fetch_byte_imm(m); | |
destval = (*opc83_word_operation[rh])(m, destval, imm); | |
if (rh != 7) | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
imm = (int8)fetch_byte_imm(m); | |
destval = (*opc83_word_operation[rh])(m, destval, imm); | |
if (rh != 7) | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
imm = (int8) fetch_byte_imm(m); | |
destval = (*opc83_word_operation[rh])(m, destval, imm); | |
if (rh != 7) | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
imm = (int8) fetch_byte_imm(m); | |
destval = (*opc83_word_operation[rh])(m, *destreg, imm); | |
if (rh != 7) | |
*destreg = destval; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x84*/ | |
static void i86op_test_byte_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 destoffset; | |
uint8 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
test_byte(m, destval, *srcreg); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
test_byte(m, destval, *srcreg); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
test_byte(m, destval, *srcreg); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
test_byte(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x85*/ | |
static void i86op_test_word_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 destoffset; | |
uint16 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
test_word(m, destval, *srcreg); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
test_word(m, destval, *srcreg); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
test_word(m, destval, *srcreg); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
test_word(m, *destreg, *srcreg); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x86*/ | |
static void i86op_xchg_byte_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 destoffset; | |
uint8 destval; | |
uint8 tmp; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
tmp = *srcreg; | |
*srcreg = destval; | |
destval = tmp; | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
tmp = *srcreg; | |
*srcreg = destval; | |
destval = tmp; | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
tmp = *srcreg; | |
*srcreg = destval; | |
destval = tmp; | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
tmp = *srcreg; | |
*srcreg = *destreg; | |
*destreg = tmp; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x87*/ | |
static void i86op_xchg_word_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 destoffset; | |
uint16 destval; | |
uint16 tmp; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
tmp = *srcreg; | |
*srcreg = destval; | |
destval = tmp; | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
tmp = *srcreg; | |
*srcreg = destval; | |
destval = tmp; | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
tmp = *srcreg; | |
*srcreg = destval; | |
destval = tmp; | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
tmp = *srcreg; | |
*srcreg = *destreg; | |
*destreg = tmp; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x88*/ | |
static void i86op_mov_byte_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 destoffset; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
store_data_byte(m,destoffset,*srcreg); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
store_data_byte(m,destoffset,*srcreg); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
store_data_byte(m,destoffset,*srcreg); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
*destreg = *srcreg; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x89*/ | |
static void i86op_mov_word_RM_R(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 destoffset; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
store_data_word(m,destoffset,*srcreg); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
store_data_word(m,destoffset,*srcreg); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
store_data_word(m,destoffset,*srcreg); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
*destreg = *srcreg; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x8a*/ | |
static void i86op_mov_byte_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint8 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = srcval; | |
break; | |
case 1: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = srcval; | |
break; | |
case 2: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_byte(m,srcoffset); | |
*destreg = srcval; | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rh); | |
srcreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
*destreg = *srcreg; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x8b*/ | |
static void i86op_mov_word_R_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint16 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = srcval; | |
break; | |
case 1: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = srcval; | |
break; | |
case 2: | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = srcval; | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rl); | |
*destreg = *srcreg; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x8c*/ | |
static void i86op_mov_word_RM_SR(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 destoffset; | |
uint16 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
srcreg = decode_rm_seg_register(m,rh); | |
destval = *srcreg; | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
srcreg = decode_rm_seg_register(m,rh); | |
destval = *srcreg; | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
srcreg = decode_rm_seg_register(m,rh); | |
destval = *srcreg; | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
srcreg = decode_rm_seg_register(m,rh); | |
*destreg = *srcreg; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x8d*/ | |
static void i86op_lea_word_R_M(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *srcreg; | |
uint16 destoffset; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destoffset=decode_rm00_address(m,rl); | |
*srcreg = destoffset; | |
break; | |
case 1: | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destoffset=decode_rm01_address(m,rl); | |
*srcreg = destoffset; | |
break; | |
case 2: | |
srcreg = DECODE_RM_WORD_REGISTER(m,rh); | |
destoffset=decode_rm10_address(m,rl); | |
*srcreg = destoffset; | |
break; | |
case 3: /* register to register */ | |
/* undefined. Do nothing. */ | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x8e*/ | |
static void i86op_mov_word_SR_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg,*srcreg; | |
uint16 srcoffset; | |
uint16 srcval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destreg = decode_rm_seg_register(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = srcval; | |
break; | |
case 1: | |
destreg = decode_rm_seg_register(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = srcval; | |
break; | |
case 2: | |
destreg = decode_rm_seg_register(m,rh); | |
srcoffset = decode_rm10_address(m,rl); | |
srcval = fetch_data_word(m,srcoffset); | |
*destreg = srcval; | |
break; | |
case 3: /* register to register */ | |
destreg = decode_rm_seg_register(m,rh); | |
srcreg = DECODE_RM_WORD_REGISTER(m,rl); | |
*destreg = *srcreg; | |
break; | |
} | |
/*\ | |
* clean up, and reset all the R_xSP pointers to the correct | |
* locations. This is about 3x too much overhead (doing all the | |
* segreg ptrs when only one is needed, but this instruction | |
* *cannot* be that common, and this isn't too much work anyway. | |
\*/ | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x8f*/ | |
static void i86op_pop_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg; | |
uint16 destoffset; | |
uint16 destval; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
if (rh != 0) | |
{ | |
halt_sys(m); | |
} | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = pop_word( m); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = pop_word(m); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = pop_word(m); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
*destreg = pop_word(m); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x90*/ | |
static void i86op_nop(PC_ENV *m) | |
{ | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x91*/ | |
static void i86op_xchg_word_AX_CX(PC_ENV *m) | |
{ | |
uint16 tmp; | |
tmp = m->R_AX; | |
m->R_AX = m->R_CX; | |
m->R_CX = tmp; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x92*/ | |
static void i86op_xchg_word_AX_DX(PC_ENV *m) | |
{ | |
uint16 tmp; | |
tmp = m->R_AX; | |
m->R_AX = m->R_DX; | |
m->R_DX = tmp; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x93*/ | |
static void i86op_xchg_word_AX_BX(PC_ENV *m) | |
{ | |
uint16 tmp; | |
tmp = m->R_AX; | |
m->R_AX = m->R_BX; | |
m->R_BX = tmp; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x94*/ | |
static void i86op_xchg_word_AX_SP(PC_ENV *m) | |
{ | |
uint16 tmp; | |
tmp = m->R_AX; | |
m->R_AX = m->R_SP; | |
m->R_SP = tmp; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x95*/ | |
static void i86op_xchg_word_AX_BP(PC_ENV *m) | |
{ | |
uint16 tmp; | |
tmp = m->R_AX; | |
m->R_AX = m->R_BP; | |
m->R_BP = tmp; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x96*/ | |
static void i86op_xchg_word_AX_SI(PC_ENV *m) | |
{ | |
uint16 tmp; | |
tmp = m->R_AX; | |
m->R_AX = m->R_SI; | |
m->R_SI = tmp; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x97*/ | |
static void i86op_xchg_word_AX_DI(PC_ENV *m) | |
{ | |
uint16 tmp; | |
tmp = m->R_AX; | |
m->R_AX = m->R_DI; | |
m->R_DI = tmp; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x98*/ | |
static void i86op_cbw(PC_ENV *m) | |
{ | |
if (m->R_AL & 0x80) | |
{ | |
m->R_AH = 0xff; | |
} | |
else | |
{ | |
m->R_AH = 0x0; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x99*/ | |
static void i86op_cwd(PC_ENV *m) | |
{ | |
if (m->R_AX & 0x8000) | |
{ | |
m->R_DX = 0xffff; | |
} | |
else | |
{ | |
m->R_DX = 0x0; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x9a*/ | |
static void i86op_call_far_IMM(PC_ENV *m) | |
{ | |
uint16 farseg,faroff; | |
faroff = fetch_word_imm(m); | |
farseg = fetch_word_imm(m); | |
/* XXX | |
HOOKED INTERRUPT VECTORS CALLING INTO OUR "BIOS" | |
WILL CAUSE PROBLEMS UNLESS ALL INTERSEGMENT STUFF IS | |
CHECKED FOR BIOS ACCESS. CHECK NEEDED HERE. | |
FOR MOMENT, LET IT ALONE. | |
*/ | |
push_word(m,m->R_CS); | |
m->R_CS = farseg; | |
push_word(m,m->R_IP); | |
m->R_IP = faroff; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x9b*/ | |
static void i86op_wait(PC_ENV *m) | |
{ | |
/* NADA. */ | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x9c*/ | |
static void i86op_pushf_word(PC_ENV *m) | |
{ | |
uint16 flags; | |
flags = m->R_FLG; | |
/* clear out *all* bits not representing flags */ | |
flags &= F_MSK; | |
/* TURN ON CHARACTERISTIC BITS OF FLAG FOR 8088 */ | |
flags |= F_ALWAYS_ON; | |
push_word(m,flags); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x9d*/ | |
static void i86op_popf_word(PC_ENV *m) | |
{ | |
m->R_FLG = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x9e*/ | |
static void i86op_sahf(PC_ENV *m) | |
{ | |
/* clear the lower bits of the flag register */ | |
m->R_FLG &= 0xffffff00; | |
/* or in the AH register into the flags register */ | |
m->R_FLG |= m->R_AH; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0x9f*/ | |
static void i86op_lahf(PC_ENV *m) | |
{ | |
m->R_AH = m->R_FLG & 0xff; | |
/*undocumented TC++ behavior??? Nope. It's documented, but | |
you have too look real hard to notice it. */ | |
m->R_AH |= 0x2; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xa0*/ | |
static void i86op_mov_AL_M_IMM(PC_ENV *m) | |
{ | |
uint16 offset; | |
uint8 destval; | |
offset = fetch_word_imm(m); | |
destval = fetch_data_byte(m,offset); | |
m->R_AL = destval; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xa1*/ | |
static void i86op_mov_AX_M_IMM(PC_ENV *m) | |
{ | |
uint16 offset; | |
uint16 destval; | |
offset = fetch_word_imm(m); | |
destval = fetch_data_word(m,offset); | |
m->R_AX = destval; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xa2*/ | |
static void i86op_mov_M_AL_IMM(PC_ENV *m) | |
{ | |
uint16 offset; | |
offset = fetch_word_imm(m); | |
store_data_byte(m,offset,m->R_AL); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xa3*/ | |
static void i86op_mov_M_AX_IMM(PC_ENV *m) | |
{ | |
uint16 offset; | |
offset = fetch_word_imm(m); | |
store_data_word(m,offset,m->R_AX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* JHH CLEANED */ | |
/*opcode=0xa4*/ | |
static void i86op_movs_byte(PC_ENV *m) | |
{ | |
uint8 val; | |
int inc; | |
if (ACCESS_FLAG(m,F_DF)) /* down */ | |
inc = -1; | |
else | |
inc = 1; | |
if (m->sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) | |
{ | |
/* dont care whether REPE or REPNE */ | |
/* move them until CX is ZERO. */ | |
while (m->R_CX != 0) | |
{ | |
val = fetch_data_byte(m,m->R_SI); | |
store_data_byte_abs(m,m->R_ES,m->R_DI,val); | |
m->R_CX -= 1; | |
m->R_SI += inc; | |
m->R_DI += inc; | |
} | |
m->sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); | |
} | |
else | |
{ | |
val = fetch_data_byte(m,m->R_SI); | |
store_data_byte_abs(m,m->R_ES,m->R_DI,val); | |
m->R_SI += inc; | |
m->R_DI += inc; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xa5*/ | |
static void i86op_movs_word(PC_ENV *m) | |
{ | |
int16 val; | |
int inc; | |
if (ACCESS_FLAG(m, F_DF)) /* down */ | |
inc = -2; | |
else | |
inc = 2; | |
if (m->sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) | |
{ | |
/* dont care whether REPE or REPNE */ | |
/* move them until CX is ZERO. */ | |
while (m->R_CX != 0) | |
{ | |
val = fetch_data_word(m,m->R_SI); | |
store_data_word_abs(m,m->R_ES,m->R_DI,val); | |
m->R_CX -= 1; | |
m->R_SI += inc; | |
m->R_DI += inc; | |
} | |
m->sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); | |
} | |
else | |
{ | |
val = fetch_data_word(m,m->R_SI); | |
store_data_word_abs(m,m->R_ES,m->R_DI,val); | |
m->R_SI += inc; | |
m->R_DI += inc; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xa6*/ | |
static void i86op_cmps_byte(PC_ENV *m) | |
{ | |
int8 val1,val2; | |
int inc; | |
if (ACCESS_FLAG(m,F_DF)) /* down */ | |
inc = -1; | |
else | |
inc = 1; | |
if (m->sysmode & SYSMODE_PREFIX_REPE) | |
{ | |
/* REPE */ | |
/* move them until CX is ZERO. */ | |
while (m->R_CX != 0) | |
{ | |
val1 = fetch_data_byte(m,m->R_SI); | |
val2 = fetch_data_byte_abs(m,m->R_ES,m->R_DI); | |
cmp_byte(m, val1,val2); | |
m->R_CX -= 1; | |
m->R_SI += inc; | |
m->R_DI += inc; | |
if (ACCESS_FLAG(m,F_ZF)==0) | |
break; | |
} | |
m->sysmode &= ~SYSMODE_PREFIX_REPE; | |
} | |
else if (m->sysmode & SYSMODE_PREFIX_REPNE) | |
{ | |
/* REPNE */ | |
/* move them until CX is ZERO. */ | |
while (m->R_CX != 0) | |
{ | |
val1 = fetch_data_byte(m,m->R_SI); | |
val2 = fetch_data_byte_abs(m,m->R_ES,m->R_DI); | |
cmp_byte(m, val1,val2); | |
m->R_CX -= 1; | |
m->R_SI += inc; | |
m->R_DI += inc; | |
if (ACCESS_FLAG(m,F_ZF)) | |
break; /* zero flag set means equal */ | |
} | |
m->sysmode &= ~SYSMODE_PREFIX_REPNE; | |
} | |
else | |
{ | |
val1 = fetch_data_byte(m,m->R_SI); | |
val2 = fetch_data_byte_abs(m,m->R_ES,m->R_DI); | |
cmp_byte(m, val1,val2); | |
m->R_SI += inc; | |
m->R_DI += inc; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xa7*/ | |
static void i86op_cmps_word(PC_ENV *m) | |
{ | |
int16 val1,val2; | |
int inc; | |
if (ACCESS_FLAG(m,F_DF)) /* down */ | |
inc = -2; | |
else | |
inc = 2; | |
if (m->sysmode & SYSMODE_PREFIX_REPE) | |
{ | |
/* REPE */ | |
/* move them until CX is ZERO. */ | |
while (m->R_CX != 0) | |
{ | |
val1 = fetch_data_word(m,m->R_SI); | |
val2 = fetch_data_word_abs(m,m->R_ES,m->R_DI); | |
cmp_word(m, val1,val2); | |
m->R_CX -= 1; | |
m->R_SI += inc; | |
m->R_DI += inc; | |
if (ACCESS_FLAG(m,F_ZF)==0) | |
break; | |
} | |
m->sysmode &= ~SYSMODE_PREFIX_REPE; | |
} | |
else if (m->sysmode & SYSMODE_PREFIX_REPNE) | |
{ | |
/* REPNE */ | |
/* move them until CX is ZERO. */ | |
while (m->R_CX != 0) | |
{ | |
val1 = fetch_data_word(m,m->R_SI); | |
val2 = fetch_data_word_abs(m,m->R_ES,m->R_DI); | |
cmp_word(m, val1,val2); | |
m->R_CX -= 1; | |
m->R_SI += inc; | |
m->R_DI += inc; | |
if (ACCESS_FLAG(m,F_ZF)) | |
break; /* zero flag set means equal */ | |
} | |
m->sysmode &= ~SYSMODE_PREFIX_REPNE; | |
} | |
else | |
{ | |
val1 = fetch_data_word(m,m->R_SI); | |
val2 = fetch_data_word_abs(m,m->R_ES,m->R_DI); | |
cmp_word(m, val1,val2); | |
m->R_SI += inc; | |
m->R_DI += inc; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xa8*/ | |
static void i86op_test_AL_IMM(PC_ENV *m) | |
{ | |
int imm; | |
imm = fetch_byte_imm(m); | |
test_byte(m, m->R_AL, imm); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xa9*/ | |
static void i86op_test_AX_IMM(PC_ENV *m) | |
{ | |
int imm; | |
imm = fetch_word_imm(m); | |
test_word(m, m->R_AX, imm); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xaa*/ | |
static void i86op_stos_byte(PC_ENV *m) | |
{ | |
int inc; | |
if (ACCESS_FLAG(m, F_DF)) /* down */ | |
inc = -1; | |
else | |
inc = 1; | |
if (m->sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) | |
{ | |
/* dont care whether REPE or REPNE */ | |
/* move them until CX is ZERO. */ | |
while (m->R_CX != 0) | |
{ | |
store_data_byte_abs(m,m->R_ES,m->R_DI,m->R_AL); | |
m->R_CX -= 1; | |
m->R_DI += inc; | |
} | |
m->sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); | |
} | |
else | |
{ | |
store_data_byte_abs(m,m->R_ES,m->R_DI,m->R_AL); | |
m->R_DI += inc; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xab*/ | |
static void i86op_stos_word(PC_ENV *m) | |
{ | |
int inc; | |
if (ACCESS_FLAG(m, F_DF)) /* down */ | |
inc = -2; | |
else | |
inc = 2; | |
if (m->sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) | |
{ | |
/* dont care whether REPE or REPNE */ | |
/* move them until CX is ZERO. */ | |
while (m->R_CX != 0) | |
{ | |
store_data_word_abs(m,m->R_ES,m->R_DI,m->R_AX); | |
m->R_CX -= 1; | |
m->R_DI += inc; | |
} | |
m->sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); | |
} | |
else | |
{ | |
store_data_word_abs(m,m->R_ES,m->R_DI,m->R_AX); | |
m->R_DI += inc; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xac*/ | |
static void i86op_lods_byte(PC_ENV *m) | |
{ | |
int inc; | |
if (ACCESS_FLAG(m,F_DF)) /* down */ | |
inc = -1; | |
else | |
inc = 1; | |
if (m->sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) | |
{ | |
/* dont care whether REPE or REPNE */ | |
/* move them until CX is ZERO. */ | |
while (m->R_CX != 0) | |
{ | |
m->R_AL = fetch_data_byte(m,m->R_SI); | |
m->R_CX -= 1; | |
m->R_SI += inc; | |
} | |
m->sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); | |
} | |
else | |
{ | |
m->R_AL = fetch_data_byte(m,m->R_SI); | |
m->R_SI += inc; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xad*/ | |
static void i86op_lods_word(PC_ENV *m) | |
{ | |
int inc; | |
if (ACCESS_FLAG(m,F_DF)) /* down */ | |
inc = -2; | |
else | |
inc = 2; | |
if (m->sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) | |
{ | |
/* dont care whether REPE or REPNE */ | |
/* move them until CX is ZERO. */ | |
while (m->R_CX != 0) | |
{ | |
m->R_AX = fetch_data_word(m,m->R_SI); | |
m->R_CX -= 1; | |
m->R_SI += inc; | |
} | |
m->sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); | |
} | |
else | |
{ | |
m->R_AX = fetch_data_word(m,m->R_SI); | |
m->R_SI += inc; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xae*/ | |
static void i86op_scas_byte(PC_ENV *m) | |
{ | |
int8 val2; | |
int inc; | |
if (ACCESS_FLAG(m,F_DF)) /* down */ | |
inc = -1; | |
else | |
inc = 1; | |
if (m->sysmode & SYSMODE_PREFIX_REPE) | |
{ | |
/* REPE */ | |
/* move them until CX is ZERO. */ | |
while (m->R_CX != 0) | |
{ | |
val2 = fetch_data_byte_abs(m,m->R_ES,m->R_DI); | |
cmp_byte(m, m->R_AL,val2); | |
m->R_CX -= 1; | |
m->R_DI += inc; | |
if (ACCESS_FLAG(m,F_ZF)==0) | |
break; | |
} | |
m->sysmode &= ~SYSMODE_PREFIX_REPE; | |
} | |
else if (m->sysmode & SYSMODE_PREFIX_REPNE) | |
{ | |
/* REPNE */ | |
/* move them until CX is ZERO. */ | |
while (m->R_CX != 0) | |
{ | |
val2 = fetch_data_byte_abs(m,m->R_ES,m->R_DI); | |
cmp_byte(m, m->R_AL,val2); | |
m->R_CX -= 1; | |
m->R_DI += inc; | |
if (ACCESS_FLAG(m,F_ZF)) | |
break; /* zero flag set means equal */ | |
} | |
m->sysmode &= ~SYSMODE_PREFIX_REPNE; | |
} | |
else | |
{ | |
val2 = fetch_data_byte_abs(m,m->R_ES,m->R_DI); | |
cmp_byte(m, m->R_AL,val2); | |
m->R_DI += inc; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xaf*/ | |
static void i86op_scas_word(PC_ENV *m) | |
{ | |
int16 val2; | |
int inc; | |
if (ACCESS_FLAG(m, F_DF)) /* down */ | |
inc = -2; | |
else | |
inc = 2; | |
if (m->sysmode & SYSMODE_PREFIX_REPE) | |
{ | |
/* REPE */ | |
/* move them until CX is ZERO. */ | |
while (m->R_CX != 0) | |
{ | |
val2 = fetch_data_word_abs(m,m->R_ES,m->R_DI); | |
cmp_word(m,m->R_AX,val2); | |
m->R_CX -= 1; | |
m->R_DI += inc; | |
if (ACCESS_FLAG(m,F_ZF)==0) | |
break; | |
} | |
m->sysmode &= ~SYSMODE_PREFIX_REPE; | |
} | |
else if (m->sysmode & SYSMODE_PREFIX_REPNE) | |
{ | |
/* REPNE */ | |
/* move them until CX is ZERO. */ | |
while (m->R_CX != 0) | |
{ | |
val2 = fetch_data_word_abs(m,m->R_ES,m->R_DI); | |
cmp_word(m, m->R_AX,val2); | |
m->R_CX -= 1; | |
m->R_DI += inc; | |
if (ACCESS_FLAG(m,F_ZF)) | |
break; /* zero flag set means equal */ | |
} | |
m->sysmode &= ~SYSMODE_PREFIX_REPNE; | |
} | |
else | |
{ | |
val2 = fetch_data_word_abs(m,m->R_ES,m->R_DI); | |
cmp_word(m, m->R_AX,val2); | |
m->R_DI += inc; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xb0*/ | |
static void i86op_mov_byte_AL_IMM(PC_ENV *m) | |
{ | |
uint8 imm; | |
imm = fetch_byte_imm(m); | |
m->R_AL = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xb1*/ | |
static void i86op_mov_byte_CL_IMM(PC_ENV *m) | |
{ | |
uint8 imm; | |
imm = fetch_byte_imm(m); | |
m->R_CL = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xb2*/ | |
static void i86op_mov_byte_DL_IMM(PC_ENV *m) | |
{ | |
uint8 imm; | |
imm = fetch_byte_imm(m); | |
m->R_DL = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xb3*/ | |
static void i86op_mov_byte_BL_IMM(PC_ENV *m) | |
{ | |
uint8 imm; | |
imm = fetch_byte_imm(m); | |
m->R_BL = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xb4*/ | |
static void i86op_mov_byte_AH_IMM(PC_ENV *m) | |
{ | |
uint8 imm; | |
imm = fetch_byte_imm(m); | |
m->R_AH = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xb5*/ | |
static void i86op_mov_byte_CH_IMM(PC_ENV *m) | |
{ | |
uint8 imm; | |
imm = fetch_byte_imm(m); | |
m->R_CH = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xb6*/ | |
static void i86op_mov_byte_DH_IMM(PC_ENV *m) | |
{ | |
uint8 imm; | |
imm = fetch_byte_imm(m); | |
m->R_DH = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xb7*/ | |
static void i86op_mov_byte_BH_IMM(PC_ENV *m) | |
{ | |
uint8 imm; | |
imm = fetch_byte_imm(m); | |
m->R_BH = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xb8*/ | |
static void i86op_mov_word_AX_IMM(PC_ENV *m) | |
{ | |
uint16 imm; | |
imm = fetch_word_imm(m); | |
m->R_AX = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xb9*/ | |
static void i86op_mov_word_CX_IMM(PC_ENV *m) | |
{ | |
uint16 imm; | |
imm = fetch_word_imm(m); | |
m->R_CX = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xba*/ | |
static void i86op_mov_word_DX_IMM(PC_ENV *m) | |
{ | |
uint16 imm; | |
imm = fetch_word_imm(m); | |
m->R_DX = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xbb*/ | |
static void i86op_mov_word_BX_IMM(PC_ENV *m) | |
{ | |
uint16 imm; | |
imm = fetch_word_imm(m); | |
m->R_BX = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xbc*/ | |
static void i86op_mov_word_SP_IMM(PC_ENV *m) | |
{ | |
uint16 imm; | |
imm = fetch_word_imm(m); | |
m->R_SP = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xbd*/ | |
static void i86op_mov_word_BP_IMM(PC_ENV *m) | |
{ | |
uint16 imm; | |
imm = fetch_word_imm(m); | |
m->R_BP = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xbe*/ | |
static void i86op_mov_word_SI_IMM(PC_ENV *m) | |
{ | |
uint16 imm; | |
imm = fetch_word_imm(m); | |
m->R_SI = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xbf*/ | |
static void i86op_mov_word_DI_IMM(PC_ENV *m) | |
{ | |
uint16 imm; | |
imm = fetch_word_imm(m); | |
m->R_DI = imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* c0 === ILLEGAL OPERAND */ | |
/* c1 === ILLEGAL OPERAND */ | |
/*opcode=0xc2*/ | |
static void i86op_ret_near_IMM(PC_ENV *m) | |
{ | |
uint16 imm; | |
imm = fetch_word_imm(m); | |
m->R_IP = pop_word(m); | |
m->R_SP += imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xc3*/ | |
static void i86op_ret_near(PC_ENV *m) | |
{ | |
m->R_IP = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xc4*/ | |
static void i86op_les_R_IMM(PC_ENV *m) | |
{ | |
uint16 mod,rh,rl; | |
uint16 *dstreg; | |
uint16 srcoffset; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
dstreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
*dstreg = fetch_data_word(m,srcoffset); | |
m->R_ES = fetch_data_word(m,srcoffset+2); | |
break; | |
case 1: | |
dstreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
*dstreg = fetch_data_word(m,srcoffset); | |
m->R_ES = fetch_data_word(m,srcoffset+2); | |
break; | |
case 2: | |
dstreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
*dstreg = fetch_data_word(m,srcoffset); | |
m->R_ES = fetch_data_word(m,srcoffset+2); | |
break; | |
case 3: /* register to register */ | |
/* UNDEFINED! */ | |
; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xc5*/ | |
static void i86op_lds_R_IMM(PC_ENV *m) | |
{ | |
uint16 mod,rh,rl; | |
uint16 *dstreg; | |
uint16 srcoffset; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
dstreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm00_address(m,rl); | |
*dstreg = fetch_data_word(m,srcoffset); | |
m->R_DS = fetch_data_word(m,srcoffset+2); | |
break; | |
case 1: | |
dstreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm01_address(m,rl); | |
*dstreg = fetch_data_word(m,srcoffset); | |
m->R_DS = fetch_data_word(m,srcoffset+2); | |
break; | |
case 2: | |
dstreg = DECODE_RM_WORD_REGISTER(m,rh); | |
srcoffset=decode_rm10_address(m,rl); | |
*dstreg = fetch_data_word(m,srcoffset); | |
m->R_DS = fetch_data_word(m,srcoffset+2); | |
break; | |
case 3: /* register to register */ | |
/* UNDEFINED! */ | |
; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xc6*/ | |
static void i86op_mov_byte_RM_IMM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg; | |
uint16 destoffset; | |
uint8 imm; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
if (rh != 0) | |
{ | |
halt_sys(m); | |
} | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
imm = fetch_byte_imm(m); | |
store_data_byte(m,destoffset,imm); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
imm = fetch_byte_imm(m); | |
store_data_byte(m,destoffset,imm); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
imm = fetch_byte_imm(m); | |
store_data_byte(m,destoffset,imm); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
imm = fetch_byte_imm(m); | |
*destreg = imm; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xc7*/ | |
static void i86op_mov_word_RM_IMM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg; | |
uint16 destoffset; | |
uint16 imm; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
if (rh != 0) | |
{ | |
halt_sys(m); | |
} | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
imm = fetch_word_imm(m); | |
store_data_word(m,destoffset,imm); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
imm = fetch_word_imm(m); | |
store_data_word(m,destoffset,imm); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
imm = fetch_word_imm(m); | |
store_data_word(m,destoffset,imm); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
imm = fetch_word_imm(m); | |
*destreg = imm; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xc8 ILLEGAL OP*/ | |
/*opcode=0xc9 ILLEGAL OP*/ | |
/*opcode=0xca*/ | |
static void i86op_ret_far_IMM(PC_ENV *m) | |
{ | |
uint16 imm; | |
imm = fetch_word_imm(m); | |
m->R_IP = pop_word(m); | |
m->R_CS = pop_word(m); | |
m->R_SP += imm; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xcb*/ | |
static void i86op_ret_far(PC_ENV *m) | |
{ | |
m->R_IP = pop_word(m); | |
m->R_CS = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xcc*/ | |
static void i86op_int3(PC_ENV *m) | |
{ | |
uint16 tmp; | |
/* access the segment register */ | |
{ | |
tmp = m->R_FLG; | |
push_word(m, tmp); | |
CLEAR_FLAG(m, F_IF); | |
CLEAR_FLAG(m, F_TF); | |
/* [JCE] If we're interrupting between a segment override (or REP override) | |
* and the following instruction, decrease IP to get back to the prefix */ | |
if (m->sysmode & (SYSMODE_SEGMASK | | |
SYSMODE_PREFIX_REPE | | |
SYSMODE_PREFIX_REPNE)) | |
{ | |
--m->R_IP; | |
} | |
push_word(m, m->R_CS); | |
push_word(m, m->R_IP); | |
/* [JCE] CS and IP were the wrong way round... */ | |
tmp = mem_access_word(m, 3 * 4); | |
m->R_IP = tmp; | |
tmp = mem_access_word(m, 3 * 4 + 2); | |
m->R_CS = tmp; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xcd*/ | |
static void i86op_int_IMM(PC_ENV *m) | |
{ | |
uint16 tmp; | |
uint8 intnum; | |
intnum = fetch_byte_imm(m); | |
{ | |
tmp = m->R_FLG; | |
push_word(m, tmp); | |
CLEAR_FLAG(m, F_IF); | |
CLEAR_FLAG(m, F_TF); | |
/* [JCE] If we're interrupting between a segment override (or REP override) | |
* and the following instruction, decrease IP to get back to the prefix */ | |
if (m->sysmode & (SYSMODE_SEGMASK | | |
SYSMODE_PREFIX_REPE | | |
SYSMODE_PREFIX_REPNE)) | |
{ | |
--m->R_IP; | |
} | |
push_word(m, m->R_CS); | |
push_word(m, m->R_IP); | |
/* [JCE] CS and IP were the wrong way round... */ | |
tmp = mem_access_word(m, intnum * 4); | |
m->R_IP = tmp; | |
tmp = mem_access_word(m, intnum * 4 + 2); | |
m->R_CS = tmp; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xce*/ | |
static void i86op_into(PC_ENV *m) | |
{ | |
uint16 tmp; | |
if (ACCESS_FLAG(m,F_OF)) | |
{ | |
{ | |
tmp = m->R_FLG; | |
push_word(m, tmp); | |
CLEAR_FLAG(m, F_IF); | |
CLEAR_FLAG(m, F_TF); | |
/* [JCE] If we're interrupting between a segment override (or REP override) | |
* and the following instruction, decrease IP to get back to the prefix */ | |
if (m->sysmode & (SYSMODE_SEGMASK | | |
SYSMODE_PREFIX_REPE | | |
SYSMODE_PREFIX_REPNE)) | |
{ | |
--m->R_IP; | |
} | |
push_word(m, m->R_CS); | |
push_word(m, m->R_IP); | |
/* [JCE] CS and IP were the wrong way round... */ | |
tmp = mem_access_word(m, 4 * 4); | |
m->R_IP = tmp; | |
tmp = mem_access_word(m, 4 * 4 + 2); | |
m->R_CS = tmp; | |
} | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xcf*/ | |
static void i86op_iret(PC_ENV *m) | |
{ | |
m->R_IP = pop_word(m); | |
m->R_CS = pop_word(m); | |
m->R_FLG = pop_word(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
static uint8 (*opcD0_byte_operation[])(PC_ENV *m,uint8 d, uint8 s) = | |
/* used by opcodes d0 and d2. */ | |
{ | |
rol_byte, | |
ror_byte, | |
rcl_byte, | |
rcr_byte, | |
shl_byte, | |
shr_byte, | |
shl_byte, /* sal_byte === shl_byte by definition */ | |
sar_byte, | |
}; | |
/* opcode=0xd0*/ | |
static void i86op_opcD0_byte_RM_1(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg; | |
uint16 destoffset; | |
uint8 destval; | |
/* Yet another weirdo special case instruction format. Part of the | |
opcode held below in "RH". Doubly nested case would | |
result, except that the decoded instruction | |
*/ | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
/* know operation, decode the mod byte to find the addressing | |
mode. */ | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
destval = (*opcD0_byte_operation[rh])(m, destval,1); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
destval = (*opcD0_byte_operation[rh])(m, destval, 1); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
destval = (*opcD0_byte_operation[rh])(m, destval, 1); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
destval = (*opcD0_byte_operation[rh])(m, *destreg, 1); | |
*destreg = destval; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
static uint16 (*opcD1_word_operation[])(PC_ENV *m,uint16 s,uint16 d) = | |
/* used by opcodes d1 and d3. */ | |
{ rol_word, | |
ror_word, | |
rcl_word, | |
rcr_word, | |
shl_word, | |
shr_word, | |
shl_word, /* sal_byte === shl_byte by definition */ | |
sar_word, | |
}; | |
/* opcode=0xd1*/ | |
static void i86op_opcD1_word_RM_1(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg; | |
uint16 destoffset; | |
uint16 destval; | |
/* Yet another weirdo special case instruction format. Part of the | |
opcode held below in "RH". Doubly nested case would | |
result, except that the decoded instruction | |
*/ | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
/* know operation, decode the mod byte to find the addressing | |
mode. */ | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
destval = (*opcD1_word_operation[rh])(m, destval,1); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
destval = (*opcD1_word_operation[rh])(m, destval, 1); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
destval = (*opcD1_word_operation[rh])(m, destval, 1); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
destval = (*opcD1_word_operation[rh])(m, *destreg, 1); | |
*destreg = destval; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xd2*/ | |
static void i86op_opcD2_byte_RM_CL(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg; | |
uint16 destoffset; | |
uint8 destval; | |
uint8 amt; | |
/* Yet another weirdo special case instruction format. Part of the | |
opcode held below in "RH". Doubly nested case would | |
result, except that the decoded instruction | |
*/ | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
amt = m->R_CL; | |
/* know operation, decode the mod byte to find the addressing | |
mode. */ | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
destval = (*opcD0_byte_operation[rh])(m, destval,amt); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
destval = (*opcD0_byte_operation[rh])(m, destval, amt); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
destval = (*opcD0_byte_operation[rh])(m, destval, amt); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
destval = (*opcD0_byte_operation[rh])(m, *destreg, amt); | |
*destreg = destval; | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xd3*/ | |
static void i86op_opcD3_word_RM_CL(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg; | |
uint16 destoffset; | |
uint16 destval; | |
uint8 amt; | |
/* Yet another weirdo special case instruction format. Part of the | |
opcode held below in "RH". Doubly nested case would | |
result, except that the decoded instruction | |
*/ | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
amt = m->R_CL; | |
/* know operation, decode the mod byte to find the addressing | |
mode. */ | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
destval = (*opcD1_word_operation[rh])(m, destval, amt); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
destval = (*opcD1_word_operation[rh])(m, destval, amt); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
destval = (*opcD1_word_operation[rh])(m, destval, amt); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: /* register to register */ | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
*destreg = (*opcD1_word_operation[rh])(m, *destreg, amt); | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
static void sys_fatal(int error, char *fmt, ...) | |
{ | |
va_list p; | |
va_start(p, fmt); | |
fprintf(stderr, "Fatal error: "); | |
if (error != 0) | |
{ | |
fprintf(stderr, "<%d>",error); | |
fprintf(stderr,"%s",strerror(error)); | |
} | |
vfprintf(stderr, fmt, p); | |
va_end(p); | |
fprintf(stderr, NLP "Exiting..." NLP); | |
exit(1); | |
} | |
/* opcode=0xd4*/ | |
static void i86op_aam(PC_ENV *m) | |
{ uint8 a; | |
a = fetch_byte_imm(m); /* this is a stupid encoding. */ | |
if (a != 10) | |
sys_fatal(0,"error decoding aam" NLP); | |
/* note the type change here --- returning AL and AH in AX. */ | |
m->R_AX = aam_word(m,m->R_AL); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xd5*/ | |
static void i86op_aad(PC_ENV *m) | |
{ | |
m->R_AX = aad_word(m,m->R_AX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xd6 ILLEGAL OPCODE */ | |
/* opcode=0xd7 */ | |
static void i86op_xlat(PC_ENV *m) | |
{ | |
uint16 addr; | |
addr = m->R_BX + (uint8)m->R_AL; | |
m->R_AL = fetch_data_byte(m,addr); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xe0*/ | |
static void i86op_loopne(PC_ENV *m) | |
{ | |
int16 ip; | |
ip = (int8)fetch_byte_imm(m); | |
ip += (int16)m->R_IP; | |
m->R_CX -= 1; | |
if (m->R_CX != 0 && !ACCESS_FLAG(m,F_ZF)) /* CX != 0 and !ZF */ | |
m->R_IP = ip; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xe1*/ | |
static void i86op_loope(PC_ENV *m) | |
{ | |
int16 ip; | |
ip = (int8)fetch_byte_imm(m); | |
ip += (int16)m->R_IP; | |
m->R_CX -= 1; | |
if (m->R_CX != 0 && ACCESS_FLAG(m,F_ZF)) /* CX != 0 and ZF */ | |
m->R_IP = ip; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xe2*/ | |
static void i86op_loop(PC_ENV *m) | |
{ | |
int16 ip; | |
ip = (int8)fetch_byte_imm(m); | |
ip += (int16)m->R_IP; | |
m->R_CX -= 1; | |
if (m->R_CX != 0) | |
m->R_IP = ip; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xe3*/ | |
static void i86op_jcxz(PC_ENV *m) | |
{ | |
int16 offset,target; | |
/* jump to byte offset if overflow flag is set */ | |
offset = (int8)fetch_byte_imm(m); /* sign extended ??? */ | |
target = (int16)m->R_IP + offset; | |
if (m->R_CX == 0) | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xe4*/ | |
static void i86op_in_byte_AL_IMM(PC_ENV *m) | |
{ | |
uint8 port; | |
port = (uint8)fetch_byte_imm(m); | |
m->R_AL = in(port); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xe5*/ | |
static void i86op_in_word_AX_IMM(PC_ENV *m) | |
{ | |
uint8 port; | |
port = (uint8)fetch_byte_imm(m); | |
m->R_AX = in(port); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xe6*/ | |
static void i86op_out_byte_IMM_AL(PC_ENV *m) | |
{ | |
uint8 port; | |
port = (uint8)fetch_byte_imm(m); | |
out(port, m->R_AL); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xe7*/ | |
static void i86op_out_word_IMM_AX(PC_ENV *m) | |
{ | |
uint8 port; | |
port = (uint8)fetch_byte_imm(m); | |
out(port, m->R_AX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xe8*/ | |
static void i86op_call_near_IMM(PC_ENV *m) | |
{ | |
int16 ip; | |
/* weird. Thought this was a signed disp! */ | |
ip = (int16)fetch_word_imm(m); | |
ip += (int16)m->R_IP; /* CHECK SIGN */ | |
push_word(m,m->R_IP); | |
m->R_IP = ip; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xe9*/ | |
static void i86op_jump_near_IMM(PC_ENV *m) | |
{ | |
int ip; | |
/* weird. Thought this was a signed disp too! */ | |
ip = (int16)fetch_word_imm(m); | |
ip += (int16)m->R_IP; /* CHECK SIGN */ | |
m->R_IP = ip; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xea*/ | |
static void i86op_jump_far_IMM(PC_ENV *m) | |
{ | |
uint16 cs,ip; | |
ip = fetch_word_imm(m); | |
cs = fetch_word_imm(m); | |
m->R_IP = ip; | |
m->R_CS = cs; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xeb*/ | |
static void i86op_jump_byte_IMM(PC_ENV *m) | |
{ | |
int8 offset; | |
uint16 target; | |
offset = (int8) fetch_byte_imm(m); /* CHECK */ | |
/* printf("jump byte imm offset=%d\n",offset);*/ | |
target = (int16) m->R_IP + offset; | |
m->R_IP = target; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xec*/ | |
static void i86op_in_byte_AL_DX(PC_ENV *m) | |
{ | |
m->R_AL = in(m->R_DX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xed*/ | |
static void i86op_in_word_AX_DX(PC_ENV *m) | |
{ | |
m->R_AX = in(m->R_DX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xee*/ | |
static void i86op_out_byte_DX_AL(PC_ENV *m) | |
{ | |
out(m->R_DX, m->R_AL); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xef*/ | |
static void i86op_out_word_DX_AX(PC_ENV *m) | |
{ | |
out(m->R_DX, m->R_AX); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xf0*/ | |
static void i86op_lock(PC_ENV *m) | |
{ | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xf1 ILLEGAL OPERATION*/ | |
/*opcode=0xf2*/ | |
static void i86op_repne(PC_ENV *m) | |
{ | |
m->sysmode |= SYSMODE_PREFIX_REPNE; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xf3*/ | |
static void i86op_repe(PC_ENV *m) | |
{ | |
m->sysmode |= SYSMODE_PREFIX_REPE; | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xf4*/ | |
static void i86op_halt(PC_ENV *m) | |
{ | |
halt_sys(m); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xf5*/ | |
static void i86op_cmc(PC_ENV *m) | |
{ | |
/* complement the carry flag. */ | |
TOGGLE_FLAG(m,F_CF); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xf6*/ | |
static void i86op_opcF6_byte_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint8 *destreg; | |
uint16 destoffset; | |
uint8 destval,srcval; | |
/* long, drawn out code follows. Double switch for a total | |
of 32 cases. */ | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: /* mod=00 */ | |
switch(rh) | |
{ | |
case 0: /* test byte imm */ | |
destoffset=decode_rm00_address(m,rl); | |
srcval = fetch_byte_imm(m); | |
destval = fetch_data_byte(m,destoffset); | |
test_byte(m, destval, srcval); | |
break; | |
case 1: | |
halt_sys(m); | |
break; | |
case 2: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
destval = not_byte(m, destval); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
destval = neg_byte(m, destval); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 4: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
mul_byte(m, destval); | |
break; | |
case 5: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
imul_byte(m, destval); | |
break; | |
case 6: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
div_byte(m, destval); | |
break; | |
case 7: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
idiv_byte(m, destval); | |
break; | |
} | |
break; /* end mod==00 */ | |
case 1: /* mod=01 */ | |
switch(rh) | |
{ | |
case 0: /* test byte imm */ | |
destoffset=decode_rm01_address(m,rl); | |
srcval = fetch_byte_imm(m); | |
destval = fetch_data_byte(m,destoffset); | |
test_byte(m, destval, srcval); | |
break; | |
case 1: | |
halt_sys(m); | |
break; | |
case 2: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
destval = not_byte(m, destval); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
destval = neg_byte(m, destval); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 4: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
mul_byte(m, destval); | |
break; | |
case 5: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
imul_byte(m, destval); | |
break; | |
case 6: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
div_byte(m, destval); | |
break; | |
case 7: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
idiv_byte(m, destval); | |
break; | |
} | |
break; /* end mod==01 */ | |
case 2: /* mod=10 */ | |
switch(rh) | |
{ | |
case 0: /* test byte imm */ | |
destoffset=decode_rm10_address(m,rl); | |
srcval = fetch_byte_imm(m); | |
destval = fetch_data_byte(m,destoffset); | |
test_byte(m, destval, srcval); | |
break; | |
case 1: | |
halt_sys(m); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
destval = not_byte(m, destval); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 3: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
destval = neg_byte(m, destval); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 4: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
mul_byte(m, destval); | |
break; | |
case 5: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
imul_byte(m, destval); | |
break; | |
case 6: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
div_byte(m, destval); | |
break; | |
case 7: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_byte(m,destoffset); | |
idiv_byte(m, destval); | |
break; | |
} | |
break; /* end mod==10 */ | |
case 3: /* mod=11 */ | |
switch(rh) | |
{ | |
case 0: /* test byte imm */ | |
destreg=DECODE_RM_BYTE_REGISTER(m,rl); | |
srcval = fetch_byte_imm(m); | |
test_byte(m, *destreg, srcval); | |
break; | |
case 1: | |
halt_sys(m); | |
break; | |
case 2: | |
destreg=DECODE_RM_BYTE_REGISTER(m,rl); | |
*destreg = not_byte(m, *destreg); | |
break; | |
case 3: | |
destreg=DECODE_RM_BYTE_REGISTER(m,rl); | |
*destreg = neg_byte(m, *destreg); | |
break; | |
case 4: | |
destreg=DECODE_RM_BYTE_REGISTER(m,rl); | |
mul_byte(m, *destreg); /*!!! */ | |
break; | |
case 5: | |
destreg=DECODE_RM_BYTE_REGISTER(m,rl); | |
imul_byte(m, *destreg); | |
break; | |
case 6: | |
destreg=DECODE_RM_BYTE_REGISTER(m,rl); | |
div_byte(m, *destreg); | |
break; | |
case 7: | |
destreg=DECODE_RM_BYTE_REGISTER(m,rl); | |
idiv_byte(m, *destreg); | |
break; | |
} | |
break; /* end mod==11 */ | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xf7*/ | |
static void i86op_opcF7_word_RM(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
uint16 *destreg; | |
uint16 destoffset; | |
uint16 destval,srcval; | |
/* long, drawn out code follows. Double switch for a total | |
of 32 cases. */ | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: /* mod=00 */ | |
switch(rh) | |
{ | |
case 0: /* test word imm */ | |
destoffset=decode_rm00_address(m,rl); | |
srcval = fetch_word_imm(m); | |
destval = fetch_data_word(m,destoffset); | |
test_word(m, destval, srcval); | |
break; | |
case 1: | |
halt_sys(m); | |
break; | |
case 2: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
destval = not_word(m, destval); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
destval = neg_word(m, destval); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 4: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
mul_word(m, destval); | |
break; | |
case 5: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
imul_word(m, destval); | |
break; | |
case 6: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
div_word(m, destval); | |
break; | |
case 7: | |
destoffset=decode_rm00_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
idiv_word(m, destval); | |
break; | |
} | |
break; /* end mod==00 */ | |
case 1: /* mod=01 */ | |
switch(rh) | |
{ | |
case 0: /* test word imm */ | |
destoffset=decode_rm01_address(m,rl); | |
srcval = fetch_word_imm(m); | |
destval = fetch_data_word(m,destoffset); | |
test_word(m, destval, srcval); | |
break; | |
case 1: | |
halt_sys(m); | |
break; | |
case 2: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
destval = not_word(m, destval); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
destval = neg_word(m, destval); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 4: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
mul_word(m, destval); | |
break; | |
case 5: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
imul_word(m, destval); | |
break; | |
case 6: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
div_word(m, destval); | |
break; | |
case 7: | |
destoffset=decode_rm01_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
idiv_word(m, destval); | |
break; | |
} | |
break; /* end mod==01 */ | |
case 2: /* mod=10 */ | |
switch(rh) | |
{ | |
case 0: /* test word imm */ | |
destoffset=decode_rm10_address(m,rl); | |
srcval = fetch_word_imm(m); | |
destval = fetch_data_word(m,destoffset); | |
test_word(m, destval, srcval); | |
break; | |
case 1: | |
halt_sys(m); | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
destval = not_word(m, destval); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 3: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
destval = neg_word(m, destval); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 4: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
mul_word(m, destval); | |
break; | |
case 5: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
imul_word(m, destval); | |
break; | |
case 6: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
div_word(m, destval); | |
break; | |
case 7: | |
destoffset=decode_rm10_address(m,rl); | |
destval = fetch_data_word(m,destoffset); | |
idiv_word(m, destval); | |
break; | |
} | |
break; /* end mod==10 */ | |
case 3: /* mod=11 */ | |
switch(rh) | |
{ | |
case 0: /* test word imm */ | |
destreg=DECODE_RM_WORD_REGISTER(m,rl); | |
srcval = fetch_word_imm(m); | |
test_word(m, *destreg, srcval); | |
break; | |
case 1: | |
halt_sys(m); | |
break; | |
case 2: | |
destreg=DECODE_RM_WORD_REGISTER(m,rl); | |
*destreg = not_word(m, *destreg); | |
break; | |
case 3: | |
destreg=DECODE_RM_WORD_REGISTER(m,rl); | |
*destreg = neg_word(m, *destreg); | |
break; | |
case 4: | |
destreg=DECODE_RM_WORD_REGISTER(m,rl); | |
mul_word(m, *destreg); /*!!! */ | |
break; | |
case 5: | |
destreg=DECODE_RM_WORD_REGISTER(m,rl); | |
imul_word(m, *destreg); | |
break; | |
case 6: | |
destreg=DECODE_RM_WORD_REGISTER(m,rl); | |
div_word(m, *destreg); | |
break; | |
case 7: | |
destreg=DECODE_RM_WORD_REGISTER(m,rl); | |
idiv_word(m, *destreg); | |
break; | |
} | |
break; /* end mod==11 */ | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xf8*/ | |
static void i86op_clc(PC_ENV *m) | |
{ | |
/* clear the carry flag. */ | |
CLEAR_FLAG(m, F_CF); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xf9*/ | |
static void i86op_stc(PC_ENV *m) | |
{ | |
/* set the carry flag. */ | |
SET_FLAG(m, F_CF); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xfa*/ | |
static void i86op_cli(PC_ENV *m) | |
{ | |
/* clear interrupts. */ | |
CLEAR_FLAG(m, F_IF); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xfb*/ | |
static void i86op_sti(PC_ENV *m) | |
{ | |
/* enable interrupts. */ | |
SET_FLAG(m, F_IF); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xfc*/ | |
static void i86op_cld(PC_ENV *m) | |
{ | |
/* clear interrupts. */ | |
CLEAR_FLAG(m, F_DF); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xfd*/ | |
static void i86op_std(PC_ENV *m) | |
{ | |
/* clear interrupts. */ | |
SET_FLAG(m, F_DF); | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xfe*/ | |
static void i86op_opcFE_byte_RM(PC_ENV *m) | |
{ | |
/* Yet another damned special case instruction. */ | |
uint16 mod,rh,rl; | |
uint8 destval; | |
uint16 destoffset; | |
uint8 *destreg; | |
/* ARRGH, ANOTHER GODDAMN SPECIAL CASE INSTRUCTION!!! */ | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
switch (rh) | |
{ | |
case 0: /* inc word ptr ... */ | |
destval = fetch_data_byte(m,destoffset); | |
destval = inc_byte(m,destval); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: /* dec word ptr ... */ | |
destval = fetch_data_byte(m,destoffset); | |
destval = dec_byte(m,destval); | |
store_data_byte(m,destoffset,destval); | |
break; | |
} | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
switch (rh) | |
{ | |
case 0: | |
destval = fetch_data_byte(m,destoffset); | |
destval = inc_byte(m,destval); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: | |
destval = fetch_data_byte(m,destoffset); | |
destval = dec_byte(m,destval); | |
store_data_byte(m,destoffset,destval); | |
break; | |
} | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
switch (rh) | |
{ | |
case 0: | |
destval = fetch_data_byte(m,destoffset); | |
destval = inc_byte(m,destval); | |
store_data_byte(m,destoffset,destval); | |
break; | |
case 1: | |
destval = fetch_data_byte(m,destoffset); | |
destval = dec_byte(m,destval); | |
store_data_byte(m,destoffset,destval); | |
break; | |
} | |
break; | |
case 3: | |
destreg = DECODE_RM_BYTE_REGISTER(m,rl); | |
switch (rh) | |
{ | |
case 0: | |
*destreg = inc_byte(m,*destreg); | |
break; | |
case 1: | |
*destreg = dec_byte(m,*destreg); | |
break; | |
} | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/*opcode=0xff*/ | |
static void i86op_opcFF_word_RM(PC_ENV *m) | |
{ | |
uint16 mod,rh,rl; | |
uint16 destval,destval2; | |
uint16 destoffset; | |
uint16 *destreg; | |
/* ANOTHER DAMN SPECIAL CASE INSTRUCTION!!! */ | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
destoffset=decode_rm00_address(m,rl); | |
switch (rh) | |
{ | |
case 0: /* inc word ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
destval = inc_word(m,destval); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: /* dec word ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
destval = dec_word(m,destval); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: /* call word ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
push_word(m,m->R_IP); | |
m->R_IP = destval; | |
break; | |
case 3: /* call far ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
destval2 = fetch_data_word(m,destoffset+2); | |
push_word(m,m->R_CS); | |
m->R_CS = destval2; | |
push_word(m,m->R_IP); | |
m->R_IP = destval; | |
break; | |
case 4: /* jmp word ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
m->R_IP = destval; | |
break; | |
case 5: /* jmp far ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
destval2 = fetch_data_word(m,destoffset+2); | |
m->R_IP = destval; | |
m->R_CS = destval2; | |
break; | |
case 6: /* push word ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
push_word(m,destval); | |
break; | |
} | |
break; | |
case 1: | |
destoffset=decode_rm01_address(m,rl); | |
switch (rh) | |
{ | |
case 0: | |
destval = fetch_data_word(m,destoffset); | |
destval = inc_word(m,destval); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destval = fetch_data_word(m,destoffset); | |
destval = dec_word(m,destval); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: /* call word ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
push_word(m,m->R_IP); | |
m->R_IP = destval; | |
break; | |
case 3: /* call far ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
destval2 = fetch_data_word(m,destoffset+2); | |
push_word(m,m->R_CS); | |
m->R_CS = destval2; | |
push_word(m,m->R_IP); | |
m->R_IP = destval; | |
break; | |
case 4: /* jmp word ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
m->R_IP = destval; | |
break; | |
case 5: /* jmp far ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
destval2 = fetch_data_word(m,destoffset+2); | |
m->R_IP = destval; | |
m->R_CS = destval2; | |
break; | |
case 6: /* push word ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
push_word(m,destval); | |
break; | |
} | |
break; | |
case 2: | |
destoffset=decode_rm10_address(m,rl); | |
switch (rh) | |
{ | |
case 0: | |
destval = fetch_data_word(m,destoffset); | |
destval = inc_word(m,destval); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 1: | |
destval = fetch_data_word(m,destoffset); | |
destval = dec_word(m,destval); | |
store_data_word(m,destoffset,destval); | |
break; | |
case 2: /* call word ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
push_word(m,m->R_IP); | |
m->R_IP = destval; | |
break; | |
case 3: /* call far ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
destval2 = fetch_data_word(m,destoffset+2); | |
push_word(m,m->R_CS); | |
m->R_CS = destval2; | |
push_word(m,m->R_IP); | |
m->R_IP = destval; | |
break; | |
case 4: /* jmp word ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
m->R_IP = destval; | |
break; | |
case 5: /* jmp far ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
destval2 = fetch_data_word(m,destoffset+2); | |
m->R_IP = destval; | |
m->R_CS = destval2; | |
break; | |
case 6: /* push word ptr ... */ | |
destval = fetch_data_word(m,destoffset); | |
push_word(m,destval); | |
break; | |
} | |
break; | |
case 3: | |
destreg = DECODE_RM_WORD_REGISTER(m,rl); | |
switch (rh) | |
{ | |
case 0: | |
*destreg = inc_word(m,*destreg); | |
break; | |
case 1: | |
*destreg = dec_word(m,*destreg); | |
break; | |
case 2: /* call word ptr ... */ | |
push_word(m,m->R_IP); | |
m->R_IP = *destreg; | |
break; | |
case 3: /* jmp far ptr ... */ | |
halt_sys(m); | |
break; | |
case 4: /* jmp ... */ | |
m->R_IP = (uint16)(*destreg); | |
break; | |
case 5: /* jmp far ptr ... */ | |
halt_sys(m); | |
break; | |
case 6: | |
push_word(m,*destreg); | |
break; | |
} | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xd8*/ | |
static void i86op_esc_coprocess_d8(PC_ENV *m) | |
{ | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xd9*/ | |
static void i86op_esc_coprocess_d9(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
decode_rm00_address(m,rl); | |
break; | |
case 1: | |
decode_rm01_address(m,rl); | |
break; | |
case 2: | |
decode_rm10_address(m,rl); | |
break; | |
case 3: /* register to register */ | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xda*/ | |
static void i86op_esc_coprocess_da(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
decode_rm00_address(m,rl); | |
break; | |
case 1: | |
decode_rm01_address(m,rl); | |
break; | |
case 2: | |
decode_rm10_address(m,rl); | |
break; | |
case 3: /* register to register */ | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xdb*/ | |
static void i86op_esc_coprocess_db(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
decode_rm00_address(m,rl); | |
break; | |
case 1: | |
decode_rm01_address(m,rl); | |
break; | |
case 2: | |
decode_rm10_address(m,rl); | |
break; | |
case 3: /* register to register */ | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xdc*/ | |
static void i86op_esc_coprocess_dc(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
decode_rm00_address(m,rl); | |
break; | |
case 1: | |
decode_rm01_address(m,rl); | |
break; | |
case 2: | |
decode_rm10_address(m,rl); | |
break; | |
case 3: /* register to register */ | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xdd*/ | |
static void i86op_esc_coprocess_dd(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
decode_rm00_address(m,rl); | |
break; | |
case 1: | |
decode_rm01_address(m,rl); | |
break; | |
case 2: | |
decode_rm10_address(m,rl); | |
break; | |
case 3: /* register to register */ | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xde*/ | |
static void i86op_esc_coprocess_de(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
decode_rm00_address(m,rl); | |
break; | |
case 1: | |
decode_rm01_address(m,rl); | |
break; | |
case 2: | |
decode_rm10_address(m,rl); | |
break; | |
case 3: /* register to register */ | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* opcode=0xdf*/ | |
static void i86op_esc_coprocess_df(PC_ENV *m) | |
{ | |
uint16 mod,rl,rh; | |
FETCH_DECODE_MODRM(m,mod,rh,rl); | |
switch (mod) | |
{ | |
case 0: | |
decode_rm00_address(m,rl); | |
break; | |
case 1: | |
decode_rm01_address(m,rl); | |
break; | |
case 2: | |
decode_rm10_address(m,rl); | |
break; | |
case 3: /* register to register */ | |
break; | |
} | |
DECODE_CLEAR_SEGOVR(m); | |
} | |
/* OPERAND TABLE */ | |
OP i86_optab[256] = { | |
/* 0x00 */ i86op_add_byte_RM_R, | |
/* 0x01 */ i86op_add_word_RM_R, | |
/* 0x02 */ i86op_add_byte_R_RM, | |
/* 0x03 */ i86op_add_word_R_RM, | |
/* 0x04 */ i86op_add_byte_AL_IMM, | |
/* 0x05 */ i86op_add_word_AX_IMM, | |
/* 0x06 */ i86op_push_ES, | |
/* 0x07 */ i86op_pop_ES, | |
/* 0x08 */ i86op_or_byte_RM_R, | |
/* 0x09 */ i86op_or_word_RM_R, | |
/* 0x0a */ i86op_or_byte_R_RM, | |
/* 0x0b */ i86op_or_word_R_RM, | |
/* 0x0c */ i86op_or_byte_AL_IMM, | |
/* 0x0d */ i86op_or_word_AX_IMM, | |
/* 0x0e */ i86op_push_CS, | |
/* 0x0f */ i86op_illegal_op, | |
/* 0x10 */ i86op_adc_byte_RM_R, | |
/* 0x11 */ i86op_adc_word_RM_R, | |
/* 0x12 */ i86op_adc_byte_R_RM, | |
/* 0x13 */ i86op_adc_word_R_RM, | |
/* 0x14 */ i86op_adc_byte_AL_IMM, | |
/* 0x15 */ i86op_adc_word_AX_IMM, | |
/* 0x16 */ i86op_push_SS, | |
/* 0x17 */ i86op_pop_SS, | |
/* 0x18 */ i86op_sbb_byte_RM_R, | |
/* 0x19 */ i86op_sbb_word_RM_R, | |
/* 0x1a */ i86op_sbb_byte_R_RM, | |
/* 0x1b */ i86op_sbb_word_R_RM, | |
/* 0x1c */ i86op_sbb_byte_AL_IMM, | |
/* 0x1d */ i86op_sbb_word_AX_IMM, | |
/* 0x1e */ i86op_push_DS, | |
/* 0x1f */ i86op_pop_DS, | |
/* 0x20 */ i86op_and_byte_RM_R, | |
/* 0x21 */ i86op_and_word_RM_R, | |
/* 0x22 */ i86op_and_byte_R_RM, | |
/* 0x23 */ i86op_and_word_R_RM, | |
/* 0x24 */ i86op_and_byte_AL_IMM, | |
/* 0x25 */ i86op_and_word_AX_IMM, | |
/* 0x26 */ i86op_segovr_ES, | |
/* 0x27 */ i86op_daa, | |
/* 0x28 */ i86op_sub_byte_RM_R, | |
/* 0x29 */ i86op_sub_word_RM_R, | |
/* 0x2a */ i86op_sub_byte_R_RM, | |
/* 0x2b */ i86op_sub_word_R_RM, | |
/* 0x2c */ i86op_sub_byte_AL_IMM, | |
/* 0x2d */ i86op_sub_word_AX_IMM, | |
/* 0x2e */ i86op_segovr_CS, | |
/* 0x2f */ i86op_das, | |
/* 0x30 */ i86op_xor_byte_RM_R, | |
/* 0x31 */ i86op_xor_word_RM_R, | |
/* 0x32 */ i86op_xor_byte_R_RM, | |
/* 0x33 */ i86op_xor_word_R_RM, | |
/* 0x34 */ i86op_xor_byte_AL_IMM, | |
/* 0x35 */ i86op_xor_word_AX_IMM, | |
/* 0x36 */ i86op_segovr_SS, | |
/* 0x37 */ i86op_aaa, | |
/* 0x38 */ i86op_cmp_byte_RM_R, | |
/* 0x39 */ i86op_cmp_word_RM_R, | |
/* 0x3a */ i86op_cmp_byte_R_RM, | |
/* 0x3b */ i86op_cmp_word_R_RM, | |
/* 0x3c */ i86op_cmp_byte_AL_IMM, | |
/* 0x3d */ i86op_cmp_word_AX_IMM, | |
/* 0x3e */ i86op_segovr_DS, | |
/* 0x3f */ i86op_aas, | |
/* 0x40 */ i86op_inc_AX, | |
/* 0x41 */ i86op_inc_CX, | |
/* 0x42 */ i86op_inc_DX, | |
/* 0x43 */ i86op_inc_BX, | |
/* 0x44 */ i86op_inc_SP, | |
/* 0x45 */ i86op_inc_BP, | |
/* 0x46 */ i86op_inc_SI, | |
/* 0x47 */ i86op_inc_DI, | |
/* 0x48 */ i86op_dec_AX, | |
/* 0x49 */ i86op_dec_CX, | |
/* 0x4a */ i86op_dec_DX, | |
/* 0x4b */ i86op_dec_BX, | |
/* 0x4c */ i86op_dec_SP, | |
/* 0x4d */ i86op_dec_BP, | |
/* 0x4e */ i86op_dec_SI, | |
/* 0x4f */ i86op_dec_DI, | |
/* 0x50 */ i86op_push_AX, | |
/* 0x51 */ i86op_push_CX, | |
/* 0x52 */ i86op_push_DX, | |
/* 0x53 */ i86op_push_BX, | |
/* 0x54 */ i86op_push_SP, | |
/* 0x55 */ i86op_push_BP, | |
/* 0x56 */ i86op_push_SI, | |
/* 0x57 */ i86op_push_DI, | |
/* 0x58 */ i86op_pop_AX, | |
/* 0x59 */ i86op_pop_CX, | |
/* 0x5a */ i86op_pop_DX, | |
/* 0x5b */ i86op_pop_BX, | |
/* 0x5c */ i86op_pop_SP, | |
/* 0x5d */ i86op_pop_BP, | |
/* 0x5e */ i86op_pop_SI, | |
/* 0x5f */ i86op_pop_DI, | |
/* 0x60 */ i86op_illegal_op, | |
/* 0x61 */ i86op_illegal_op, | |
/* 0x62 */ i86op_illegal_op, | |
/* 0x63 */ i86op_illegal_op, | |
/* 0x64 */ i86op_illegal_op, | |
/* 0x65 */ i86op_illegal_op, | |
/* 0x66 */ i86op_illegal_op, | |
/* 0x67 */ i86op_illegal_op, | |
/* 0x68 */ i86op_illegal_op, | |
/* 0x69 */ i86op_illegal_op, | |
/* 0x6a */ i86op_illegal_op, | |
/* 0x6b */ i86op_illegal_op, | |
/* 0x6c */ i86op_illegal_op, | |
/* 0x6d */ i86op_illegal_op, | |
/* 0x6e */ i86op_illegal_op, | |
/* 0x6f */ i86op_illegal_op, | |
/* 0x70 */ i86op_jump_near_O, | |
/* 0x71 */ i86op_jump_near_NO, | |
/* 0x72 */ i86op_jump_near_B, | |
/* 0x73 */ i86op_jump_near_NB, | |
/* 0x74 */ i86op_jump_near_Z, | |
/* 0x75 */ i86op_jump_near_NZ, | |
/* 0x76 */ i86op_jump_near_BE, | |
/* 0x77 */ i86op_jump_near_NBE, | |
/* 0x78 */ i86op_jump_near_S, | |
/* 0x79 */ i86op_jump_near_NS, | |
/* 0x7a */ i86op_jump_near_P, | |
/* 0x7b */ i86op_jump_near_NP, | |
/* 0x7c */ i86op_jump_near_L, | |
/* 0x7d */ i86op_jump_near_NL, | |
/* 0x7e */ i86op_jump_near_LE, | |
/* 0x7f */ i86op_jump_near_NLE, | |
/* 0x80 */ i86op_opc80_byte_RM_IMM, | |
/* 0x81 */ i86op_opc81_word_RM_IMM, | |
/* 0x82 */ i86op_opc82_byte_RM_IMM, | |
/* 0x83 */ i86op_opc83_word_RM_IMM, | |
/* 0x84 */ i86op_test_byte_RM_R, | |
/* 0x85 */ i86op_test_word_RM_R, | |
/* 0x86 */ i86op_xchg_byte_RM_R, | |
/* 0x87 */ i86op_xchg_word_RM_R, | |
/* 0x88 */ i86op_mov_byte_RM_R, | |
/* 0x89 */ i86op_mov_word_RM_R, | |
/* 0x8a */ i86op_mov_byte_R_RM, | |
/* 0x8b */ i86op_mov_word_R_RM, | |
/* 0x8c */ i86op_mov_word_RM_SR, | |
/* 0x8d */ i86op_lea_word_R_M, | |
/* 0x8e */ i86op_mov_word_SR_RM, | |
/* 0x8f */ i86op_pop_RM, | |
/* 0x90 */ i86op_nop, | |
/* 0x91 */ i86op_xchg_word_AX_CX, | |
/* 0x92 */ i86op_xchg_word_AX_DX, | |
/* 0x93 */ i86op_xchg_word_AX_BX, | |
/* 0x94 */ i86op_xchg_word_AX_SP, | |
/* 0x95 */ i86op_xchg_word_AX_BP , | |
/* 0x96 */ i86op_xchg_word_AX_SI , | |
/* 0x97 */ i86op_xchg_word_AX_DI , | |
/* 0x98 */ i86op_cbw, | |
/* 0x99 */ i86op_cwd, | |
/* 0x9a */ i86op_call_far_IMM, | |
/* 0x9b */ i86op_wait, | |
/* 0x9c */ i86op_pushf_word, | |
/* 0x9d */ i86op_popf_word, | |
/* 0x9e */ i86op_sahf, | |
/* 0x9f */ i86op_lahf, | |
/* 0xa0 */ i86op_mov_AL_M_IMM, | |
/* 0xa1 */ i86op_mov_AX_M_IMM, | |
/* 0xa2 */ i86op_mov_M_AL_IMM, | |
/* 0xa3 */ i86op_mov_M_AX_IMM, | |
/* 0xa4 */ i86op_movs_byte, | |
/* 0xa5 */ i86op_movs_word, | |
/* 0xa6 */ i86op_cmps_byte, | |
/* 0xa7 */ i86op_cmps_word, | |
/* 0xa8 */ i86op_test_AL_IMM, | |
/* 0xa9 */ i86op_test_AX_IMM, | |
/* 0xaa */ i86op_stos_byte, | |
/* 0xab */ i86op_stos_word, | |
/* 0xac */ i86op_lods_byte, | |
/* 0xad */ i86op_lods_word, | |
/* 0xac */ i86op_scas_byte, | |
/* 0xad */ i86op_scas_word, | |
/* 0xb0 */ i86op_mov_byte_AL_IMM, | |
/* 0xb1 */ i86op_mov_byte_CL_IMM, | |
/* 0xb2 */ i86op_mov_byte_DL_IMM, | |
/* 0xb3 */ i86op_mov_byte_BL_IMM, | |
/* 0xb4 */ i86op_mov_byte_AH_IMM, | |
/* 0xb5 */ i86op_mov_byte_CH_IMM, | |
/* 0xb6 */ i86op_mov_byte_DH_IMM, | |
/* 0xb7 */ i86op_mov_byte_BH_IMM, | |
/* 0xb8 */ i86op_mov_word_AX_IMM, | |
/* 0xb9 */ i86op_mov_word_CX_IMM, | |
/* 0xba */ i86op_mov_word_DX_IMM, | |
/* 0xbb */ i86op_mov_word_BX_IMM, | |
/* 0xbc */ i86op_mov_word_SP_IMM, | |
/* 0xbd */ i86op_mov_word_BP_IMM, | |
/* 0xbe */ i86op_mov_word_SI_IMM, | |
/* 0xbf */ i86op_mov_word_DI_IMM, | |
/* 0xc0 */ i86op_illegal_op, | |
/* 0xc1 */ i86op_illegal_op, | |
/* 0xc2 */ i86op_ret_near_IMM, | |
/* 0xc3 */ i86op_ret_near, | |
/* 0xc4 */ i86op_les_R_IMM, | |
/* 0xc5 */ i86op_lds_R_IMM, | |
/* 0xc6 */ i86op_mov_byte_RM_IMM, | |
/* 0xc7 */ i86op_mov_word_RM_IMM, | |
/* 0xc8 */ i86op_illegal_op, | |
/* 0xc9 */ i86op_illegal_op, | |
/* 0xca */ i86op_ret_far_IMM, | |
/* 0xcb */ i86op_ret_far, | |
/* 0xcc */ i86op_int3, | |
/* 0xcd */ i86op_int_IMM, | |
/* 0xce */ i86op_into, | |
/* 0xcf */ i86op_iret, | |
/* 0xd0 */ i86op_opcD0_byte_RM_1, | |
/* 0xd1 */ i86op_opcD1_word_RM_1, | |
/* 0xd2 */ i86op_opcD2_byte_RM_CL, | |
/* 0xd3 */ i86op_opcD3_word_RM_CL, | |
/* 0xd4 */ i86op_aam, | |
/* 0xd5 */ i86op_aad, | |
/* 0xd6 */ i86op_illegal_op, | |
/* 0xd7 */ i86op_xlat, | |
/* 0xd8 */ i86op_esc_coprocess_d8, | |
/* 0xd9 */ i86op_esc_coprocess_d9, | |
/* 0xda */ i86op_esc_coprocess_da, | |
/* 0xdb */ i86op_esc_coprocess_db, | |
/* 0xdc */ i86op_esc_coprocess_dc, | |
/* 0xdd */ i86op_esc_coprocess_dd, | |
/* 0xde */ i86op_esc_coprocess_de, | |
/* 0xdf */ i86op_esc_coprocess_df, | |
/* 0xe0 */ i86op_loopne, | |
/* 0xe1 */ i86op_loope, | |
/* 0xe2 */ i86op_loop, | |
/* 0xe3 */ i86op_jcxz, | |
/* 0xe4 */ i86op_in_byte_AL_IMM, | |
/* 0xe5 */ i86op_in_word_AX_IMM, | |
/* 0xe6 */ i86op_out_byte_IMM_AL, | |
/* 0xe7 */ i86op_out_word_IMM_AX, | |
/* 0xe8 */ i86op_call_near_IMM, | |
/* 0xe9 */ i86op_jump_near_IMM, | |
/* 0xea */ i86op_jump_far_IMM, | |
/* 0xeb */ i86op_jump_byte_IMM, | |
/* 0xec */ i86op_in_byte_AL_DX, | |
/* 0xed */ i86op_in_word_AX_DX, | |
/* 0xee */ i86op_out_byte_DX_AL, | |
/* 0xef */ i86op_out_word_DX_AX, | |
/* 0xf0 */ i86op_lock, | |
/* 0xf1 */ i86op_illegal_op, | |
/* 0xf2 */ i86op_repne, | |
/* 0xf3 */ i86op_repe, | |
/* 0xf4 */ i86op_halt, | |
/* 0xf5 */ i86op_cmc, | |
/* 0xf6 */ i86op_opcF6_byte_RM, | |
/* 0xf7 */ i86op_opcF7_word_RM, | |
/* 0xf8 */ i86op_clc, | |
/* 0xf9 */ i86op_stc, | |
/* 0xfa */ i86op_cli, | |
/* 0xfb */ i86op_sti, | |
/* 0xfc */ i86op_cld, | |
/* 0xfd */ i86op_std, | |
/* 0xfe */ i86op_opcFE_byte_RM, | |
/* 0xff */ i86op_opcFF_word_RM, | |
}; |