/* i8088.c: Intel 8086/8088 CPU simulator 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. This software was modified by Bill Beech, Mar 2011, from the software GDE of Jim Hudgens as provided with the SIMH AltairZ80 emulation package. I modified it to allow emulation of Intel iSBC Single Board Computers. Copyright (c) 2011, William A. Beech Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of William A. Beech shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from William A. Beech. cpu 8088 CPU 17 Mar 11 WAB Original code The register state for the 8088 CPU is: AX<0:15> AH/AL Register Pair BX<0:15> BH/BL Register Pair CX<0:15> CH/CL Register Pair DX<0:15> DH/DL Register Pair SI<0:15> Source Index Register DI<0:15> Destination Index Register BP<0:15> Base Pointer SP<0:15> Stack Pointer CS<0:15> Code Segment Register DS<0:15> Date Segment Register SS<0:15> Stack Segment Register ES<0:15> Extra Segment Register IP<0:15> Program Counter PSW<0:15> Program Status Word - Contains the following flags: AF Auxillary Flag CF Carry Flag OF Overflow Flag SF Sign Flag PF Parity Flag ZF Zero Flag DF Direction Flag IF Interrupt Enable Flag TF Trap Flag in bit positions: 15 8 7 0 |--|--|--|--|OF|DF|IF|TF|SF|ZF|--|AF|--|PF|--|CF| The 8088 is an 8-bit CPU, which uses 16-bit offset and segment registers in combination with a dedicated adder to address up to 1MB of memory directly. The offset register is added to the segment register shifted left 4 places to obtain the 20-bit address. The CPU utilizes two separate processing units - the Execution Unit (EU) and the Bus Interface Unit (BIU). The EU executes instructions. The BIU fetches instructions, reads operands and writes results. The two units can operate independently of one another and are able, under most circumstances, to extensively overlap instruction fetch with execution. The BIUs of the 8086 and 8088 are functionally identical, but are implemented differently to match the structure and performance characteristics of their respective buses. The almost 300 instructions come in 1, 2, 3, 4, 5, 6 and 7-byte flavors. This routine is the simulator for the 8088. It is called from the simulator control program to execute instructions in simulated memory, starting at the simulated IP. It runs until 'reason' is set non-zero. General notes: 1. Reasons to stop. The simulator can be stopped by: HALT instruction I/O error in I/O simulator Invalid OP code (if ITRAP is set on CPU) 2. Interrupts. There are 256 possible levels of interrupt, and in effect they do a hardware CALL instruction to one of 256 possible low memory addresses. 3. Non-existent memory. On the 8088, reads to non-existent memory return 0FFh, and writes are ignored. Some algorithms were pulled from the GDE Dos/IP Emulator by Jim Hudgens */ /* This algorithm was pulled from the GDE Dos/IP Emulator by Jim Hudgens CARRY CHAIN CALCULATION. This represents a somewhat expensive calculation which is apparently required to emulate the setting of the OF and AF flag. The latter is not so important, but the former is. The overflow flag is the XOR of the top two bits of the carry chain for an addition (similar for subtraction). Since we do not want to simulate the addition in a bitwise manner, we try to calculate the carry chain given the two operands and the result. So, given the following table, which represents the addition of two bits, we can derive a formula for the carry chain. a b cin r cout 0 0 0 0 0 0 0 1 1 0 0 1 0 1 0 0 1 1 0 1 1 0 0 1 0 1 0 1 0 1 1 1 0 0 1 1 1 1 1 1 Construction of table for cout: ab r \ 00 01 11 10 |------------------ 0 | 0 1 1 1 1 | 0 0 1 0 By inspection, one gets: cc = ab + r'(a + b) That represents alot of operations, but NO CHOICE.... BORROW CHAIN CALCULATION. The following table represents the subtraction of two bits, from which we can derive a formula for the borrow chain. a b bin r bout 0 0 0 0 0 0 0 1 1 1 0 1 0 1 1 0 1 1 0 1 1 0 0 1 0 1 0 1 0 0 1 1 0 0 0 1 1 1 1 1 Construction of table for cout: ab r \ 00 01 11 10 |------------------ 0 | 0 1 0 0 1 | 1 1 1 0 By inspection, one gets: bc = a'b + r(a' + b) Segment register selection and overrides are handled as follows: If there is a segment override, the register number is stored in seg_ovr. If there is no override, seg_ovr is zero. Seg_ovr is set to zero after each instruction except segment override instructions. Get_ea sets the value of seg_reg to the override if present otherwise to the default value for the registers used in the effective address calculation. The get/put_smword/byte routines use the register number in seg_reg to obtain the segment value to calculate the absolute memory address for the operation. */ #include #include "multibus_defs.h" #define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */ #define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) #define UNIT_V_CHIP (UNIT_V_UF+1) /* 8088 or 8086 */ #define UNIT_CHIP (1 << UNIT_V_CHIP) /* Flag values to set proper positions in PSW */ #define CF 0x0001 #define PF 0x0004 #define AF 0x0010 #define ZF 0x0040 #define SF 0x0080 #define TF 0x0100 #define IF 0x0200 #define DF 0x0400 #define OF 0x0800 /* Macros to handle the flags in the PSW 8088 has top 4 bits of the flags set to 1 also, bit#1 is set. This is (not well) documented behavior. */ #define PSW_ALWAYS_ON (0xF002) /* for 8086 */ #define PSW_MSK (CF|PF|AF|ZF|SF|TF|IF|DF|OF) #define TOGGLE_FLAG(FLAG) (PSW ^= FLAG) #define SET_FLAG(FLAG) (PSW |= FLAG) #define CLR_FLAG(FLAG) (PSW &= ~FLAG) #define GET_FLAG(FLAG) (PSW & FLAG) #define CONDITIONAL_SET_FLAG(COND,FLAG) \ if (COND) SET_FLAG(FLAG); else CLR_FLAG(FLAG) /* union of byte and word registers */ union { uint8 b[2]; /* two bytes */ uint16 w; /* one word */ } A, B, C, D; /* storage for AX, BX, CX and DX */ /* macros for byte registers */ #define AH (A.b[1]) #define AL (A.b[0]) #define BH (B.b[1]) #define BL (B.b[0]) #define CH (C.b[1]) #define CL (C.b[0]) #define DH (D.b[1]) #define DL (D.b[0]) /* macros for word registers */ #define AX (A.w) #define BX (B.w) #define CX (C.w) #define DX (D.w) /* macros for handling IP and SP */ #define INC_IP1 (++IP & ADDRMASK20) /* increment IP one byte */ #define INC_IP2 ((IP += 2) & ADDRMASK20) /* increment IP two bytes */ /* storage for the rest of the registers */ int32 DI; /* Source Index Register */ int32 SI; /* Destination Index Register */ int32 BP; /* Base Pointer Register */ int32 SP; /* Stack Pointer Register */ int32 CS; /* Code Segment Register */ int32 DS; /* Data Segment Register */ int32 SS; /* Stack Segment Register */ int32 ES; /* Extra Segment Register */ int32 IP; /* Program Counter */ int32 PSW; /* Program Status Word (Flags) */ int32 saved_PC = 0; /* saved program counter */ int32 int_req = 0; /* Interrupt request */ int32 chip = 0; /* 0 = 8088 chip, 1 = 8086 chip */ #define CHIP_8088 0 /* processor types */ #define CHIP_8086 1 #define CHIP_80188 2 #define CHIP_80186 3 #define CHIP_80286 4 int32 seg_ovr = 0; /* segment override register */ int32 seg_reg = 0; /* segment register to use for EA */ #define SEG_NONE 0 /* segmenr override register values */ #define SEG_CS 8 #define SEG_DS 9 #define SEG_ES 10 #define SEG_SS 11 int32 PCX; /* External view of IP */ /* handle prefix instructions */ uint32 sysmode = 0; /* prefix flags */ #define SYSMODE_SEG_DS_SS 0x01 #define SYSMODE_SEGOVR_CS 0x02 #define SYSMODE_SEGOVR_DS 0x04 #define SYSMODE_SEGOVR_ES 0x08 #define SYSMODE_SEGOVR_SS 0x10 #define SYSMODE_SEGMASK (SYSMODE_SEG_DS_SS | SYSMODE_SEGOVR_CS | \ SYSMODE_SEGOVR_DS | SYSMODE_SEGOVR_ES | SYSMODE_SEGOVR_SS) #define SYSMODE_PREFIX_REPE 0x20 #define SYSMODE_PREFIX_REPNE 0x40 /* function prototypes */ int32 sign_ext(int32 val); int32 fetch_byte(int32 flag); int32 fetch_word(void); int32 parity(int32 val); void i86_intr_raise(uint8 num); uint32 get_rbyte(uint32 reg); uint32 get_rword(uint32 reg); void put_rbyte(uint32 reg, uint32 val); void put_rword(uint32 reg, uint32 val); uint32 get_ea(uint32 mrr); void set_segreg(uint32 reg); void get_mrr_dec(uint32 mrr, uint32 *mod, uint32 *reg, uint32 *rm); /* emulator primitives */ uint8 aad_word(uint16 d); uint16 aam_word(uint8 d); uint8 adc_byte(uint8 d, uint8 s); uint16 adc_word(uint16 d, uint16 s); uint8 add_byte(uint8 d, uint8 s); uint16 add_word(uint16 d, uint16 s); uint8 and_byte(uint8 d, uint8 s); uint16 cmp_word(uint16 d, uint16 s); uint8 cmp_byte(uint8 d, uint8 s); uint16 and_word(uint16 d, uint16 s); uint8 dec_byte(uint8 d); uint16 dec_word(uint16 d); void div_byte(uint8 s); void div_word(uint16 s); void idiv_byte(uint8 s); void idiv_word(uint16 s); void imul_byte(uint8 s); void imul_word(uint16 s); uint8 inc_byte(uint8 d); uint16 inc_word(uint16 d); void mul_byte(uint8 s); void mul_word(uint16 s); uint8 neg_byte(uint8 s); uint16 neg_word(uint16 s); uint8 not_byte(uint8 s); uint16 not_word(uint16 s); uint8 or_byte(uint8 d, uint8 s); uint16 or_word(uint16 d, uint16 s); void push_word(uint16 val); uint16 pop_word(void); uint8 rcl_byte(uint8 d, uint8 s); uint16 rcl_word(uint16 d, uint16 s); uint8 rcr_byte(uint8 d, uint8 s); uint16 rcr_word(uint16 d, uint16 s); uint8 rol_byte(uint8 d, uint8 s); uint16 rol_word(uint16 d, uint16 s); uint8 ror_byte(uint8 d, uint8 s); uint16 ror_word(uint16 d, uint16 s); uint8 shl_byte(uint8 d, uint8 s); uint16 shl_word(uint16 d, uint16 s); uint8 shr_byte(uint8 d, uint8 s); uint16 shr_word(uint16 d, uint16 s); uint8 sar_byte(uint8 d, uint8 s); uint16 sar_word(uint16 d, uint16 s); uint8 sbb_byte(uint8 d, uint8 s); uint16 sbb_word(uint16 d, uint16 s); uint8 sub_byte(uint8 d, uint8 s); uint16 sub_word(uint16 d, uint16 s); void test_byte(uint8 d, uint8 s); void test_word(uint16 d, uint16 s); uint8 xor_byte(uint8 d, uint8 s); uint16 xor_word(uint16 d, uint16 s); int32 get_smbyte(int32 segreg, int32 addr); int32 get_smword(int32 segreg, int32 addr); void put_smbyte(int32 segreg, int32 addr, int32 val); void put_smword(int32 segreg, int32 addr, int32 val); /* simulator routines */ int32 sim_instr(void); t_stat i8088_reset (DEVICE *dptr); t_stat i8088_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat i8088_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); /* external references */ //extern t_stat i8088_reset (DEVICE *dptr); /* Multibus memory read and write absolute address routines */ extern int32 get_mbyte(int32 addr); extern int32 get_mword(int32 addr); extern void put_mbyte(int32 addr, int32 val); extern void put_mword(int32 addr, int32 val); extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ /* This is the I/O configuration table. There are 65536 possible device addresses, if a device is plugged to a port it's routine address is here, 'nulldev' means no device is available */ struct idev { int32 (*routine)(); }; extern struct idev dev_table[]; /* 8088 CPU data structures i8088_dev CPU device descriptor i8088_unit CPU unit descriptor i8088_reg CPU register list i8088_mod CPU modifiers list */ UNIT i8088_unit = { UDATA (NULL, 0, 0) }; REG i8088_reg[] = { { HRDATA (IP, saved_PC, 16) }, /* must be first for sim_PC */ { HRDATA (AX, AX, 16) }, { HRDATA (BX, BX, 16) }, { HRDATA (CX, CX, 16) }, { HRDATA (DX, DX, 16) }, { HRDATA (DI, DI, 16) }, { HRDATA (SI, SI, 16) }, { HRDATA (BP, BP, 16) }, { HRDATA (SP, SP, 16) }, { HRDATA (CS, CS, 16) }, { HRDATA (DS, DS, 16) }, { HRDATA (SS, SS, 16) }, { HRDATA (ES, ES, 16) }, { HRDATA (PSW, PSW, 16) }, { HRDATA (WRU, sim_int_char, 8) }, { NULL } }; MTAB i8088_mod[] = { { UNIT_CHIP, UNIT_CHIP, "8086", "8086", NULL }, { UNIT_CHIP, 0, "8088", "8088", NULL }, { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, { 0 } }; DEBTAB i8088_debug[] = { { "ALL", DEBUG_all }, { "FLOW", DEBUG_flow }, { "READ", DEBUG_read }, { "WRITE", DEBUG_write }, { "LEV1", DEBUG_level1 }, { "LEV2", DEBUG_level2 }, { "REG", DEBUG_reg }, { "ASM", DEBUG_asm }, { NULL } }; DEVICE i8088_dev = { "I8088", //name &i8088_unit, //units i8088_reg, //registers i8088_mod, //modifiers 1, //numunits 16, //aradix 20, //awidth 1, //aincr 16, //dradix 8, //dwidth &i8088_ex, //examine &i8088_dep, //deposit &i8088_reset, //reset NULL, //boot NULL, //attach NULL, //detach NULL, //ctxt DEV_DEBUG, //flags 0, //dctrl i8088_debug, //debflags NULL, //msize NULL //lname }; uint8 xor_3_tab[] = { 0, 1, 1, 0 }; int32 IP; static const char *opcode[] = { "ADD ", "ADD ", "ADD ", "ADD ", /* 0x00 */ "ADD AL,", "ADD AX,", "PUSH ES", "POP ES", "OR ", "OR ", "OR ", "OR ", "OR AL,", "OR AX,", "PUSH CS", "???", "ADC ", "ADC ", "ADC ", "ADC ", /* 0x10 */ "ADC AL,", "ADC AX,", "PUSH SS", "RPOP SS", "SBB ", "SBB ", "SBB ", "SBB ", "SBB AL,", "SBB AX,", "PUSH DS", "POP DS", "AND ", "AND ", "AND ", "AND ", /* 0x20 */ "AND AL,", "AND AX,", "ES:", "DAA", "SUB ", "SUB ", "SUB ", "SUB ", "SUB AL,", "SUB AX,", "CS:", "DAS", "XOR ", "XOR ", "XOR ", "XOR ", /* 0x30 */ "XOR AL,", "XOR AX,", "SS:", "AAA", "CMP ", "CMP ", "CMP ", "CMP ", "CMP AL,", "CMP AX,", "DS:", "AAS", "INC AX", "INC CX", "INC DX", "INC BX", /* 0x40 */ "INC SP", "INC BP", "INC SI", "INC DI", "DEC AX", "DEC CX", "DEC DX", "DEC BX", "DEC SP", "DEC BP", "DEC SI", "DEC DI", "PUSH AX", "PUSH CX", "PUSH DX", "PUSH BX", /* 0x50 */ "PUSH SP", "PUSH BP", "PUSH SI", "PUSH DI", "POP AX", "POP CX", "POP DX", "POP BX", "POP SP", "POP BP", "POP SI", "POP DI", "???", "???", "???", "???", /* 0x60 */ "???", "???", "???", "???", "PUSH ", "IMUL ", "PUSH ", "IMUL ", "INSB", "INSW", "OUTSB", "OUTSW", "JO ", "JNO ", "JC ", "JNC", /* 0x70 */ "JZ ", "JNZ ", "JNA ", "JA", "JS ", "JNS ", "JP ", "JNP ", "JL ", "JNL ", "JLE ", "JNLE", "???", "???", "???", "???", /* 0x80 */ "TEST ", "TEST ", "XCHG ", "XCHG ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "LEA ", "MOV ", "POP ", "NOP", "XCHG AX,CX", "XCHG AX,DX", "XCHG AX,BX",/* 0x90 */ "XCHG AX,SP", "XCHG AX,BP", "XCHG AX,SI", "XCHG AX,DI", "CBW", "CWD", "CALL ", "WAIT", "PUSHF", "POPF", "SAHF", "LAHF", "MOV AL,", "MOV AX,", "MOV ", "MOV ", /* 0xA0 */ "MOVSB", "MOVSW", "CMPSB", "CMPSW", "TEST AL,", "TEST AX,", "STOSB", "STOSW", "LODSB", "LODSW", "SCASB", "SCASW", "MOV AL,", "MOV CL,", "MOV DL,", "MOV BL,", /* 0xB0 */ "MOV AH,", "MOV CH,", "MOV DH,", "MOV BH,", "MOV AX,", "MOV CX,", "MOV DX,", "MOV BX,", "MOV SP,", "MOV BP,", "MOV SI,", "MOV DI," " ", " ", "RET ", "RET ", /* 0xC0 */ "LES ", "LDS ", "MOV ", "MOV ", "???", "???", "RET ", "RET", "INT 3", "INT ", "INTO", "IRET", " ", " ", " ", " ", /* 0xD0 */ "AAM", "AAD", "???", "XLATB", "ESC ", "ESC ", "ESC ", "ESC ", "ESC ", "ESC ", "ESC ", "ESC ", "LOOPNZ ", "LOOPZ ", "LOOP", "JCXZ", /* 0xE0 */ "IN AL,", "IN AX,", "OUT ", "OUT ", "CALL ", "JMP ", "JMP ", "JMP ", "IN AL,DX", "IN AX,DX", "OUT DX,AL", "OUT DX,AX", "LOCK", "???", "REPNZ", "REPZ", /* 0xF0 */ "HLT", "CMC", " ", " ", "CLC", "STC", "CLI", "STI", "CLD", "STD", "???", "???" }; int32 oplen[256] = { 1,3,1,1,1,1,2,1,0,1,1,1,1,1,2,1, 0,3,1,1,1,1,2,1,0,1,1,1,1,1,2,1, 0,3,3,1,1,1,2,1,0,1,3,1,1,1,2,1, 0,3,3,1,1,1,2,1,0,1,3,1,1,1,2,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,3,3,3,1,2,1,1,1,3,0,3,3,2,1, 1,1,3,2,3,1,2,1,1,0,3,2,3,0,2,1, 1,1,3,1,3,1,2,1,1,1,3,1,3,0,2,1, 1,1,3,1,3,1,2,1,1,1,3,1,3,0,2,1 }; int32 sim_instr (void) { extern int32 sim_interval; int32 IR, OP, DAR, reason, hi, lo, carry, i, adr; int32 MRR, REG, EA, MOD, RM, DISP, VAL, DATA, OFF, SEG, INC, VAL1; IP = saved_PC & ADDRMASK16; /* load local IP */ reason = 0; /* clear stop reason */ /* Main instruction fetch/decode loop */ while (reason == 0) { /* loop until halted */ if (i8088_dev.dctrl & DEBUG_asm) sim_printf("\n"); if (i8088_dev.dctrl & DEBUG_reg) { sim_printf("Regs: AX=%04X BX=%04X CX=%04X DX=%04X SP=%04X BP=%04X SI=%04X DI=%04X IP=%04X\n", AX, BX, CX, DX, SP, BP, SI, DI, IP); sim_printf("Segs: CS=%04X DS=%04X ES=%04X SS=%04X ", CS, DS, ES, SS); sim_printf("Flags: %04X\n", PSW); } if (sim_interval <= 0) { /* check clock queue */ if (reason = sim_process_event ()) break; } if (int_req > 0) { /* interrupt? */ /* 8088 interrupts not implemented yet. */ } /* end interrupt */ if (sim_brk_summ && sim_brk_test (IP, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; } sim_interval--; /* countdown clock */ PCX = IP; IR = OP = fetch_byte(0); /* fetch instruction */ /* Handle below all operations which refer to registers or register pairs. After that, a large switch statement takes care of all other opcodes */ /* data transfer instructions */ /* arithmetic instructions */ /* bit manipulation instructions */ /* string manipulation instructions */ /* control transfer instructions */ /* processor control instructions */ /* The Big Instruction Decode Switch */ switch (IR) { /* data transfer instructions */ /* arithmetic instructions */ case 0x00: /* ADD byte - REG = REG + (EA) */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = add_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = add_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x01: /* ADD word - (EA) = (EA) + REG */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = add_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smword(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = add_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rword(REG, VAL); /* store result */ } break; case 0x02: /* ADD byte - REG = REG + (EA) */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = add_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = add_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x03: /* ADD word - (EA) = (EA) + REG */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = adc_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smbyte(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = adc_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x04: /* ADD byte - AL = AL + DATA */ DATA = fetch_byte(1); VAL = add_byte(AL, DATA); /* do operation */ AL = VAL; /* store result */ break; case 0x05: /* ADD word - (EA) = (EA) + REG */ DATA = fetch_word(); VAL = add_word(AX, DATA); /* do operation */ AX = VAL; /* store result */ break; case 0x06: /* PUSH ES */ push_word(ES); break; case 0x07: /* POP ES */ ES = pop_word(); break; case 0x08: /* OR byte - REG = REG OR (EA) */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = or_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = or_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x09: /* OR word - (EA) = (EA) OR REG */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = or_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smword(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = or_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rword(REG, VAL); /* store result */ } break; case 0x0A: /* OR byte - REG = REG OR (EA) */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = or_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = or_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x0B: /* OR word - (EA) = (EA) OR REG */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = or_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smbyte(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = or_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x0C: /* OR byte - AL = AL OR DATA */ DATA = fetch_byte(1); VAL = or_byte(AL, DATA); /* do operation */ AL = VAL; /* store result */ break; case 0x0D: /* OR word - (EA) = (EA) OR REG */ DATA = fetch_word(); VAL = or_word(AX, DATA); /* do operation */ AX = VAL; /* store result */ break; case 0x0E: /* PUSH CS */ push_word(CS); break; /* 0x0F - Not implemented on 8086/8088 */ case 0x10: /* ADC byte - REG = REG + (EA) + CF */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = adc_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = adc_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x11: /* ADC word - (EA) = (EA) + REG + CF */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = adc_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smword(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = adc_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x12: /* ADC byte - REG = REG + (EA) + CF */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = adc_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = adc_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x13: /* ADC word - (EA) = (EA) + REG + CF */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = adc_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smbyte(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = adc_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x14: /* ADC byte - AL = AL + DATA + CF */ DATA = fetch_byte(1); VAL = adc_byte(AL, DATA); /* do operation */ AL = VAL; /* store result */ break; case 0x15: /* ADC word - (EA) = (EA) + REG + CF */ DATA = fetch_word(); VAL = adc_word(AX, DATA); /* do operation */ AX = VAL; /* store result */ break; case 0x16: /* PUSH SS */ push_word(SS); break; case 0x17: /* POP SS */ SS = pop_word(); break; case 0x18: /* SBB byte - REG = REG - (EA) - CF */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = sbb_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = sbb_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x19: /* SBB word - (EA) = (EA) - REG - CF */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = sbb_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smword(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = sbb_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x1A: /* SBB byte - REG = REG - (EA) - CF */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = sbb_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = sbb_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x1B: /* SBB word - (EA) = (EA) - REG - CF */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = sbb_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smbyte(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = sbb_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x1C: /* SBB byte - AL = AL - DATA - CF */ DATA = fetch_byte(1); VAL = sbb_byte(AL, DATA); /* do operation */ AL = VAL; /* store result */ break; case 0x1D: /* SBB word - (EA) = (EA) - REG - CF */ DATA = fetch_word(); VAL = sbb_word(AX, DATA); /* do operation */ AX = VAL; /* store result */ break; case 0x1E: /* PUSH DS */ push_word(DS); break; case 0x1F: /* POP DS */ DS = pop_word(); break; case 0x20: /* AND byte - REG = REG AND (EA) */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = and_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = and_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x21: /* AND word - (EA) = (EA) AND REG */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = and_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smword(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = and_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x22: /* AND byte - REG = REG AND (EA) */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = and_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = and_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x23: /* AND word - (EA) = (EA) AND REG */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = and_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smbyte(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = and_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x24: /* AND byte - AL = AL AND DATA */ DATA = fetch_byte(1); VAL = and_byte(AL, DATA); /* do operation */ AL = VAL; /* store result */ break; case 0x25: /* AND word - (EA) = (EA) AND REG */ DATA = fetch_word(); VAL = and_word(AX, DATA); /* do operation */ AX = VAL; /* store result */ break; case 0x26: /* ES: - segment override prefix */ seg_ovr = SEG_ES; sysmode |= SYSMODE_SEGOVR_ES; break; case 0x27: /* DAA */ if (((AL & 0xF) > 9) || GET_FLAG(AF)) { AL += 6; SET_FLAG(AF); } if ((AL > 0x9F) || GET_FLAG(CF)) { AL += 0x60; SET_FLAG(CF); } break; case 0x28: /* SUB byte - REG = REG - (EA) */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = sub_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = sub_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x29: /* SUB word - (EA) = (EA) - REG */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = sub_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smword(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = sub_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x2A: /* SUB byte - REG = REG - (EA) */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = sub_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = sub_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x2B: /* SUB word - (EA) = (EA) - REG */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = sub_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smbyte(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = sub_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x2C: /* SUB byte - AL = AL - DATA */ DATA = fetch_byte(1); VAL = sub_byte(AL, DATA); /* do operation */ AL = VAL; /* store result */ break; case 0x2D: /* SUB word - (EA) = (EA) - REG */ DATA = fetch_word(); VAL = sub_word(AX, DATA); /* do operation */ AX = VAL; /* store result */ break; case 0x2E: /* DS: - segment override prefix */ seg_ovr = SEG_DS; sysmode |= SYSMODE_SEGOVR_DS; break; case 0x2F: /* DAS */ if (((AL & 0xF) > 9) || GET_FLAG(AF)) { AL -= 6; SET_FLAG(AF); } if ((AL > 0x9F) || GET_FLAG(CF)) { AL -= 0x60; SET_FLAG(CF); } break; case 0x30: /* XOR byte - REG = REG XOR (EA) */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = xor_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = xor_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x31: /* XOR word - (EA) = (EA) XOR REG */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = xor_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smword(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = xor_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x32: /* XOR byte - REG = REG XOR (EA) */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = xor_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = xor_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x33: /* XOR word - (EA) = (EA) XOR REG */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = xor_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smbyte(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = xor_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x34: /* XOR byte - AL = AL XOR DATA */ DATA = fetch_byte(1); VAL = xor_byte(AL, DATA); /* do operation */ AL = VAL; /* store result */ break; case 0x35: /* XOR word - (EA) = (EA) XOR REG */ DATA = fetch_word(); VAL = xor_word(AX, DATA); /* do operation */ AX = VAL; /* store result */ break; case 0x36: /* SS: - segment override prefix */ seg_ovr = SEG_SS; sysmode |= SYSMODE_SEGOVR_SS; break; case 0x37: /* AAA */ if (((AL & 0xF) > 9) || GET_FLAG(AF)) { AL += 6; AH++; SET_FLAG(AF); } CONDITIONAL_SET_FLAG(GET_FLAG(AF), CF); AL &= 0xF; break; case 0x38: /* CMP byte - CMP (REG, (EA)) */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = xor_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = xor_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x39: /* CMP word - CMP ((EA), REG) */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = xor_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smword(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = xor_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x3A: /* CMP byte - CMP (REG, (EA)) */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = xor_byte(get_rbyte(REG), get_smbyte(seg_reg, EA)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } else { /* RM is second register */ VAL = xor_byte(get_rbyte(REG), get_rbyte(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x3B: /* CMP word - CMP ((EA), REG) */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = xor_word(get_rword(REG), get_smword(seg_reg, EA)); /* do operation */ put_smbyte(seg_reg, EA, VAL); /* store result */ } else { /* RM is second register */ VAL = xor_word(get_rword(REG), get_rword(RM)); /* do operation */ put_rbyte(REG, VAL); /* store result */ } break; case 0x3C: /* CMP byte - CMP (AL, DATA) */ DATA = fetch_byte(1); VAL = xor_byte(AL, DATA); /* do operation */ AL = VAL; /* store result */ break; case 0x3D: /* CMP word - CMP ((EA), REG) */ DATA = fetch_word(); VAL = xor_word(AX, DATA); /* do operation */ AX = VAL; /* store result */ break; case 0x3E: /* DS: - segment override prefix */ seg_ovr = SEG_DS; sysmode |= SYSMODE_SEGOVR_DS; break; case 0x3F: /* AAS */ if (((AL & 0xF) > 9) || GET_FLAG(AF)) { AL -= 6; AH--; SET_FLAG(AF); } CONDITIONAL_SET_FLAG(GET_FLAG(AF), CF); AL &= 0xF; break; case 0x40: /* INC AX */ AX = inc_word(AX); break; case 0x41: /* INC CX */ CX = inc_word(CX); break; case 0x42: /* INC DX */ DX = inc_word(DX); break; case 0x43: /* INC BX */ BX = inc_word(BX); break; case 0x44: /* INC SP */ SP = inc_word(SP); break; case 0x45: /* INC BP */ BP = inc_word(BP); break; case 0x46: /* INC SI */ SI = inc_word(SI); break; case 0x47: /* INC DI */ DI = inc_word(DI); break; case 0x48: /* DEC AX */ AX = dec_word(AX); break; case 0x49: /* DEC CX */ CX = dec_word(CX); break; case 0x4A: /* DEC DX */ DX = dec_word(DX); break; case 0x4B: /* DEC BX */ BX = dec_word(BX); break; case 0x4C: /* DEC SP */ SP = dec_word(SP); break; case 0x4D: /* DEC BP */ BP = dec_word(BP); break; case 0x4E: /* DEC SI */ SI = dec_word(SI); break; case 0x4F: /* DEC DI */ DI = dec_word(DI); break; case 0x50: /* PUSH AX */ push_word(AX); break; case 0x51: /* PUSH CX */ push_word(CX); break; case 0x52: /* PUSH DX */ push_word(DX); break; case 0x53: /* PUSH BX */ push_word(BX); break; case 0x54: /* PUSH SP */ push_word(SP); break; case 0x55: /* PUSH BP */ push_word(BP); break; case 0x56: /* PUSH SI */ push_word(SI); break; case 0x57: /* PUSH DI */ push_word(DI); break; case 0x58: /* POP AX */ AX = pop_word(); break; case 0x59: /* POP CX */ CX = pop_word(); break; case 0x5A: /* POP DX */ DX = pop_word(); break; case 0x5B: /* POP BX */ BX = pop_word(); break; case 0x5C: /* POP SP */ SP = pop_word(); break; case 0x5D: /* POP BP */ BP = pop_word(); break; case 0x5E: /* POP SI */ SI = pop_word(); break; case 0x5F: /* POP DI */ DI = pop_word(); break; /* 0x60 - 0x6F - Not implemented on 8086/8088 */ case 0x70: /* JO short label */ /* jump to byte offset if overflow flag is set */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if (GET_FLAG(OF)) IP = EA; break; case 0x71: /* JNO short label */ /* jump to byte offset if overflow flag is clear */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if (!GET_FLAG(OF)) IP = EA; break; case 0x72: /* JB/JNAE/JC short label */ /* jump to byte offset if carry flag is set. */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if (GET_FLAG(CF)) IP = EA; break; case 0x73: /* JNB/JAE/JNC short label */ /* jump to byte offset if carry flsg is clear */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if (!GET_FLAG(CF)) IP = EA; break; case 0x74: /* JE/JZ short label */ /* jump to byte offset if zero flag is set */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if (GET_FLAG(ZF)) IP = EA; break; case 0x75: /* JNE/JNZ short label */ /* jump to byte offset if zero flag is clear */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if (!GET_FLAG(ZF)) IP = EA; break; case 0x76: /* JBE/JNA short label */ /* jump to byte offset if carry flag is set or if the zero flag is set. */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if (GET_FLAG(CF) || GET_FLAG(ZF)) IP = EA; break; case 0x77: /* JNBE/JA short label */ /* jump to byte offset if carry flag is clear and if the zero flag is clear */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if (!(GET_FLAG(CF) || GET_FLAG(ZF))) IP = EA; break; case 0x78: /* JS short label */ /* jump to byte offset if sign flag is set */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if (GET_FLAG(SF)) IP = EA; break; case 0x79: /* JNS short label */ /* jump to byte offset if sign flag is clear */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if (!GET_FLAG(SF)) IP = EA; break; case 0x7A: /* JP/JPE short label */ /* jump to byte offset if parity flag is set (even) */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if (GET_FLAG(PF)) IP = EA; break; case 0x7B: /* JNP/JPO short label */ /* jump to byte offset if parity flsg is clear (odd) */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if (!GET_FLAG(PF)) IP = EA; break; case 0x7C: /* JL/JNGE short label */ /* jump to byte offset if sign flag not equal to overflow flag. */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if ((GET_FLAG(SF) != 0) ^ (GET_FLAG(OF) != 0)) IP = EA; break; case 0x7D: /* JNL/JGE short label */ /* jump to byte offset if sign flag equal to overflow flag. */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if ((GET_FLAG(SF) != 0) == (GET_FLAG(OF) != 0)) IP = EA; break; case 0x7E: /* JLE/JNG short label */ /* jump to byte offset if sign flag not equal to overflow flag or the zero flag is set */ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if (((GET_FLAG(SF) != 0) ^ (GET_FLAG(OF) != 0)) || GET_FLAG(ZF)) IP = EA; break; case 0x7F: /* JNLE/JG short label */ /* jump to byte offset if sign flag equal to overflow flag. and the zero flag is clear*/ OFF = sign_ext(fetch_byte(1)); EA = (IP + OFF) & ADDRMASK16; if (((GET_FLAG(SF) != 0) == (GET_FLAG(OF) != 0)) || !GET_FLAG(ZF)) IP = EA; break; case 0x80: /* byte operands */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ DATA = fetch_byte(1); /* must be done after DISP is collected */ switch(REG) { case 0: VAL = add_byte(get_smbyte(seg_reg, EA), DATA); /* ADD mem8, immed8 */ break; case 1: VAL = or_byte(get_smbyte(seg_reg, EA), DATA); /* OR mem8, immed8 */ break; case 2: VAL = adc_byte(get_smbyte(seg_reg, EA), DATA); /* ADC mem8, immed8 */ break; case 3: VAL = sbb_byte(get_smbyte(seg_reg, EA), DATA); /* SBB mem8, immed8 */ break; case 4: VAL = and_byte(get_smbyte(seg_reg, EA), DATA); /* AND mem8, immed8 */ break; case 5: VAL = sub_byte(get_smbyte(seg_reg, EA), DATA); /* SUB mem8, immed8 */ break; case 6: VAL = xor_byte(get_smbyte(seg_reg, EA), DATA); /* XOR mem8, immed8 */ break; case 7: VAL = cmp_byte(get_smbyte(seg_reg, EA), DATA); /* CMP mem8, immed8 */ break; } put_rbyte(EA, VAL); /* store result */ } else { /* RM is second register */ switch(REG) { case 0: VAL = add_byte(get_rbyte(RM), DATA); /* ADD REG8, immed8 */ break; case 1: VAL = or_byte(get_rbyte(RM), DATA); /* OR REG8, immed8 */ break; case 2: VAL = adc_byte(get_rbyte(RM), DATA); /* ADC REG8, immed8 */ break; case 3: VAL = sbb_byte(get_rbyte(RM), DATA); /* SBB REG8, immed8 */ break; case 4: VAL = and_byte(get_rbyte(RM), DATA); /* AND REG8, immed8 */ break; case 5: VAL = sub_byte(get_rbyte(RM), DATA); /* SUB REG8, immed8 */ break; case 6: VAL = xor_byte(get_rbyte(RM), DATA); /* XOR REG8, immed8 */ break; case 7: VAL = cmp_byte(get_rbyte(RM), DATA); /* CMP REG8, immed8 */ break; } put_rbyte(REG, VAL); /* store result */ } break; case 0x81: /* word operands */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ DATA = fetch_byte(1) << 8; /* must be done after DISP is collected */ DATA |= fetch_byte(1); switch(REG) { case 0: VAL = add_word(get_smword(seg_reg, EA), DATA); /* ADD mem16, immed16 */ break; case 1: VAL = or_word(get_smword(seg_reg, EA), DATA); /* OR mem16, immed16 */ break; case 2: VAL = adc_word(get_smword(seg_reg, EA), DATA); /* ADC mem16, immed16 */ break; case 3: VAL = sbb_word(get_smword(seg_reg, EA), DATA); /* SBB mem16, immed16 */ break; case 4: VAL = and_word(get_smword(seg_reg, EA), DATA); /* AND mem16, immed16 */ break; case 5: VAL = sub_word(get_smword(seg_reg, EA), DATA); /* SUB mem16, immed16 */ break; case 6: VAL = xor_word(get_smword(seg_reg, EA), DATA); /* XOR mem16, immed16 */ break; case 7: VAL = cmp_word(get_smword(seg_reg, EA), DATA); /* CMP mem16, immed16 */ break; } put_rword(EA, VAL); /* store result */ } else { /* RM is second register */ switch(REG) { case 0: VAL = add_word(get_rword(RM), DATA); /* ADD reg16, immed16 */ break; case 1: VAL = or_word(get_rword(RM), DATA); /* OR reg16, immed16 */ break; case 2: VAL = adc_word(get_rword(RM), DATA); /* ADC reg16, immed16 */ break; case 3: VAL = sbb_word(get_rword(RM), DATA); /* SBB reg16, immed16 */ break; case 4: VAL = and_word(get_rword(RM), DATA); /* AND reg16, immed16 */ break; case 5: VAL = sub_word(get_rword(RM), DATA); /* SUB reg16, immed16 */ break; case 6: VAL = xor_word(get_rword(RM), DATA); /* XOR reg16, immed16 */ break; case 7: VAL = cmp_word(get_rword(RM), DATA); /* CMP reg16, immed16 */ break; } put_rword(RM, VAL); /* store result */ } break; case 0x82: /* byte operands */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ DATA = fetch_byte(1); /* must be done after DISP is collected */ switch(REG) { case 0: VAL = add_byte(get_smbyte(seg_reg, EA), DATA); /* ADD mem8, immed8 */ break; case 2: VAL = adc_byte(get_smbyte(seg_reg, EA), DATA); /* ADC mem8, immed8 */ break; case 3: VAL = sbb_byte(get_smbyte(seg_reg, EA), DATA); /* SBB mem8, immed8 */ break; case 5: VAL = sub_byte(get_smbyte(seg_reg, EA), DATA); /* SUB mem8, immed8 */ break; case 7: VAL = cmp_byte(get_smbyte(seg_reg, EA), DATA); /* CMP mem8, immed8 */ break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } put_rbyte(EA, VAL); /* store result */ } else { /* RM is second register */ switch(REG) { case 0: VAL = add_byte(get_rbyte(RM), DATA); /* ADD reg8, immed8 */ break; case 2: VAL = adc_byte(get_rbyte(RM), DATA); /* ADC reg8, immed8 */ break; case 3: VAL = sbb_byte(get_rbyte(RM), DATA); /* SBB reg8, immed8 */ break; case 5: VAL = sub_byte(get_rbyte(RM), DATA); /* SUB reg8, immed8 */ break; case 7: VAL = cmp_byte(get_rbyte(RM), DATA); /* CMP reg8, immed8 */ break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } put_rbyte(REG, VAL); /* store result */ } break; case 0x83: /* word operands */ MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ DATA = fetch_byte(1) << 8; /* must be done after DISP is collected */ if (DATA & 0x80) DATA |= 0xFF00; else DATA &= 0xFF; switch(REG) { case 0: VAL = add_word(get_smword(seg_reg, EA), DATA); /* ADD mem16, immed8-SX */ break; case 2: VAL = adc_word(get_smword(seg_reg, EA), DATA); /* ADC mem16, immed8-SX */ break; case 3: VAL = sbb_word(get_smword(seg_reg, EA), DATA); /* SBB mem16, immed8-SX */ break; case 5: VAL = sub_word(get_smword(seg_reg, EA), DATA); /* SUB mem16, immed8-SX */ break; case 7: VAL = cmp_word(get_smword(seg_reg, EA), DATA); /* CMP mem16, immed8-SX */ break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } put_rword(EA, VAL); /* store result */ } else { /* RM is second register */ switch(REG) { case 0: VAL = add_word(get_rword(RM), DATA); /* ADD reg16, immed8-SX */ break; case 2: VAL = adc_word(get_rword(RM), DATA); /* ADC reg16, immed8-SX */ break; case 3: VAL = sbb_word(get_rword(RM), DATA); /* SBB reg16, immed8-SX */ break; case 5: VAL = sub_word(get_rword(RM), DATA); /* CUB reg16, immed8-SX */ break; case 7: VAL = cmp_word(get_rword(RM), DATA); /* CMP reg16, immed8-SX */ break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } put_rword(RM, VAL); /* store result */ } break; case 0x84: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ test_byte(get_smbyte(seg_reg, EA),get_rbyte(REG)); /* TEST mem8, reg8 */ } else { test_byte(get_rbyte(REG),get_rbyte(RM)); /* TEST reg8, reg8 */ } break; case 0x85: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ test_word(get_smword(seg_reg, EA),get_rword(REG)); /* TEST mem16, reg16 */ } else { test_word(get_rword(REG),get_rword(RM)); /* TEST reg16, reg16 */ } break; case 0x86: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = get_rbyte(REG);/* XCHG mem8, reg8 */ put_rbyte(REG, get_smbyte(seg_reg, EA)); put_smbyte(seg_reg, EA, VAL); } else { VAL = get_rbyte(RM);/* XCHG reg8, reg8 */ put_rbyte(RM, get_rbyte(REG)); put_rbyte(REG, VAL); } break; case 0x87: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ VAL = get_rword(REG);/* XCHG mem16, reg16 */ put_rword(REG, get_smword(seg_reg, EA)); put_smword(seg_reg, EA, VAL); } else { VAL = get_rword(RM);/* XCHG reg16, reg16 */ put_rword(RM, get_rword(REG)); put_rword(REG, VAL); } break; case 0x88: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ put_smbyte(seg_reg, EA, get_rbyte(REG)); /* MOV mem8, reg8 */ } else put_rbyte(REG, get_rbyte(RM)); /* MOV reg8, reg8 */ break; case 0x89: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ put_smword(seg_reg, EA, get_rword(REG)); /* MOV mem16, reg16 */ } else put_rword(REG, get_rword(RM)); /* MOV reg16, reg16 */ break; case 0x8A: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ put_rbyte(REG, get_smbyte(seg_reg, EA)); /* MOV reg8, mem8 */ } else put_rbyte(REG, get_rbyte(RM)); /* MOV reg8, reg8 */ break; case 0x8B: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ put_rword(REG, get_smword(seg_reg, EA)); /* MOV reg16, mem16 */ } else put_rword(REG, get_rword(RM)); /* MOV reg16, reg16 */ break; case 0x8C: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ switch(REG) { case 0: /* MOV mem16, ES */ put_smword(seg_reg, EA, ES); break; case 1: /* MOV mem16, CS */ put_smword(seg_reg, EA, CS); break; case 2: /* MOV mem16, SS */ put_smword(seg_reg, EA, SS); break; case 3: /* MOV mem16, DS */ put_smword(seg_reg, EA, DS); break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } } else { switch(REG) { case 0: /* MOV reg16, ES */ put_rword(RM, ES); break; case 1: /* MOV reg16, CS */ put_rword(RM, CS); break; case 2: /* MOV reg16, SS */ put_rword(RM, SS); break; case 3: /* MOV reg16, DS */ put_rword(RM, DS); break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } } break; case 0x8D: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ put_rword(REG, EA); /* LEA reg16, mem16 */ } else { reason = STOP_OPCODE; IP -= 2; } break; case 0x8E: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ switch(REG) { case 0: /* MOV ES, mem16 */ ES = get_smword(seg_reg, EA); break; case 1: /* MOV CS, mem16 */ CS = get_smword(seg_reg, EA); break; case 2: /* MOV SS, mem16 */ SS = get_smword(seg_reg, EA); break; case 3: /* MOV DS, mem16 */ DS = get_smword(seg_reg, EA); break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } } else { switch(REG) { case 0: /* MOV ES, reg16 */ ES = get_rword(RM); break; case 1: /* MOV CS, reg16 */ CS = get_rword(RM); break; case 2: /* MOV SS, reg16 */ SS = get_rword(RM); break; case 3: /* MOV DS, reg16 */ DS = get_rword(RM); break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } } break; case 0x8f: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ put_smword(seg_reg, EA, pop_word()); } else { reason = STOP_OPCODE; IP -= 2; } break; case 0x90: /* NOP */ break; case 0x91: /* XCHG AX, CX */ VAL = AX; AX = CX; CX = VAL; break; case 0x92: /* XCHG AX, DX */ VAL = AX; AX = DX; DX = VAL; break; case 0x93: /* XCHG AX, BX */ VAL = AX; AX = BX; BX = VAL; break; case 0x94: /* XCHG AX, SP */ VAL = AX; AX = SP; SP = VAL; break; case 0x95: /* XCHG AX, BP */ VAL = AX; AX = BP; BP = VAL; break; case 0x96: /* XCHG AX, SI */ VAL = AX; AX = SI; SI = VAL; break; case 0x97: /* XCHG AX, DI */ VAL = AX; AX = DI; DI = VAL; break; case 0x98: /* cbw */ if (AL & 0x80) AH = 0xFF; else AH = 0; break; case 0x99: /* cbw */ if (AX & 0x8000) DX = 0xffff; else DX = 0x0; break; case 0x9A: /* CALL FAR proc */ OFF = fetch_word(); /* do operation */ SEG = fetch_word(); push_word(CS); CS = SEG; push_word(IP); IP = OFF; break; case 0x9B: /* WAIT */ break; case 0x9C: /* PUSHF */ VAL = PSW; VAL &= PSW_MSK; VAL |= PSW_ALWAYS_ON; push_word(VAL); break; case 0x9D: /* POPF */ PSW = pop_word(); break; case 0x9E: /* SAHF */ PSW &= 0xFFFFFF00; PSW |= AH; break; case 0x9F: /* LAHF */ AH = PSW & 0xFF; AH |= 0x2; break; case 0xA0: /* MOV AL, mem8 */ OFF = fetch_word(); set_segreg(SEG_DS); /* to allow segment override */ AL = get_smbyte(seg_reg, OFF); break; case 0xA1: /* MOV AX, mem16 */ OFF = fetch_word(); set_segreg(SEG_DS); /* to allow segment override */ AX = get_smword(seg_reg, OFF); break; case 0xA2: /* MOV mem8, AL */ OFF = fetch_word(); set_segreg(SEG_DS); /* to allow segment override */ put_smbyte(seg_reg, OFF, AL); break; case 0xA3: /* MOV mem16, AX */ OFF = fetch_word(); set_segreg(SEG_DS); /* to allow segment override */ put_smword(seg_reg, OFF, AX); break; case 0xA4: /* MOVS dest-str8, src-str8 */ if (GET_FLAG(DF)) /* down */ INC = -1; else INC = 1; while (CX != 0) { VAL = get_smbyte(seg_reg, SI); put_smbyte(ES, DI, VAL); CX--; SI += INC; DI += INC; } break; case 0xA5: /* MOVS dest-str16, src-str16 */ if (GET_FLAG(DF)) /* down */ INC = -2; else INC = 2; while (CX != 0) { VAL = get_smword(seg_reg, SI); put_smword(ES, DI, VAL); CX--; SI += INC; DI += INC; } break; case 0xA6: /* CMPS dest-str8, src-str8 */ if (GET_FLAG(DF)) /* down */ INC = -1; else INC = 1; while (CX != 0) { VAL = get_smbyte(seg_reg, SI); VAL1 = get_smbyte(ES, DI); cmp_byte(VAL, VAL1); CX--; SI += INC; DI += INC; if (GET_FLAG(ZF) == 0) break; } break; case 0xA7: /* CMPS dest-str16, src-str16 */ if (GET_FLAG(DF)) /* down */ INC = -2; else INC = 2; while (CX != 0) { VAL = get_smword(seg_reg, SI); VAL1 = get_smword(ES, DI); cmp_word(VAL, VAL1); CX--; SI += INC; DI += INC; if (GET_FLAG(ZF) == 0) break; } break; case 0xA8: /* TEST AL, immed8 */ VAL = fetch_byte(1); test_byte(AL, VAL); break; case 0xA9: /* TEST AX, immed8 */ VAL = fetch_word(); test_word(AX, VAL); break; case 0xAA: /* STOS dest-str8 */ if (GET_FLAG(DF)) /* down */ INC = -1; else INC = 1; if (sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { while (CX != 0) { put_smbyte(ES, DI, AL); CX--; DI += INC; } sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); } else { put_smbyte(ES, DI, AL); DI += INC; } break; case 0xAB: /* STOS dest-str16 */ if (GET_FLAG(DF)) /* down */ INC = -1; else INC = 1; if (sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { while (CX != 0) { put_smword(ES, DI, AX); CX--; DI += INC; } sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); } else { put_smword(ES, DI, AL); DI += INC; } break; case 0xAC: /* LODS dest-str8 */ if (GET_FLAG(DF)) /* down */ INC = -1; else INC = 1; set_segreg(SEG_DS); /* allow overrides */ if (sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { while (CX != 0) { AL = get_smbyte(seg_reg, SI); CX--; SI += INC; } sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); } else { AL = get_smbyte(seg_reg, SI); SI += INC; } break; case 0xAD: /* LODS dest-str16 */ if (GET_FLAG(DF)) /* down */ INC = -1; else INC = 1; set_segreg(SEG_DS); /* allow overrides */ if (sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { while (CX != 0) { AX = get_smword(seg_reg, SI); CX--; SI += INC; } sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); } else { AX = get_smword(seg_reg, SI); SI += INC; } break; case 0xAE: /* SCAS dest-str8 */ if (GET_FLAG(DF)) /* down */ INC = -1; else INC = 1; if (sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { while (CX != 0) { VAL = get_smbyte(ES, DI); cmp_byte(AL, VAL); CX--; DI += INC; if (GET_FLAG(ZF) == 0) break; } sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); } else { VAL = get_smbyte(ES, DI); cmp_byte(AL, VAL); DI += INC; } break; case 0xAF: /* SCAS dest-str16 */ if (GET_FLAG(DF)) /* down */ INC = -2; else INC = 2; if (sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { while (CX != 0) { VAL = get_smword(ES, DI); cmp_word(AX, VAL); CX--; DI += INC; if (GET_FLAG(ZF) == 0) break; } sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); } else { VAL = get_smword(ES, DI); cmp_byte(AL, VAL); DI += INC; } break; case 0xB0: /* MOV AL,immed8 */ AL = fetch_byte(1); break; case 0xB1: /* MOV CL,immed8 */ CL = fetch_byte(1); break; case 0xB2: /* MOV DL,immed8 */ DL = fetch_byte(1); break; case 0xB3: /* MOV BL,immed8 */ BL = fetch_byte(1); break; case 0xB4: /* MOV AH,immed8 */ AH = fetch_byte(1); break; case 0xB5: /* MOV CH,immed8 */ CH = fetch_byte(1); break; case 0xB6: /* MOV DH,immed8 */ DH = fetch_byte(1); break; case 0xB7: /* MOV BH,immed8 */ BH = fetch_byte(1); break; case 0xB8: /* MOV AX,immed16 */ AX = fetch_word(); break; case 0xB9: /* MOV CX,immed16 */ CX = fetch_word(); break; case 0xBA: /* MOV DX,immed16 */ DX = fetch_word(); break; case 0xBB: /* MOV BX,immed16 */ BX = fetch_word(); break; case 0xBC: /* MOV SP,immed16 */ SP = fetch_word(); break; case 0xBD: /* MOV BP,immed16 */ BP = fetch_word(); break; case 0xBE: /* MOV SI,immed16 */ SI = fetch_word(); break; case 0xBF: /* MOV DI,immed16 */ DI = fetch_word(); break; /* 0xC0 - 0xC1 - Not implemented on 8086/8088 */ case 0xC2: /* RET immed16 (intrasegment) */ OFF = fetch_word(); IP = pop_word(); SP += OFF; break; case 0xC3: /* RET (intrasegment) */ IP = pop_word(); break; case 0xC4: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ put_rword(REG, get_smword(seg_reg, EA)); /* LES mem16 */ ES = get_smword(seg_reg, EA + 2); } else { // put_rword(REG, get_rword(RM)); /* LES reg16 */ // ES = get_rword(RM) + 2; /* not defined for 8086 */ reason = STOP_OPCODE; IP -= 2; } break; case 0xC5: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ put_rword(REG, get_smword(seg_reg, EA)); /* LDS mem16 */ DS = get_smword(seg_reg, EA + 2); } else { // put_rword(REG, get_rword(RM)); /* LDS reg16 */ // DS = get_rword(RM) + 2; /* not defined for 8086 */ reason = STOP_OPCODE; IP -= 2; } break; case 0xC6: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (REG) { /* has to be 0 */ reason = STOP_OPCODE; IP -= 2; } if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ DATA = fetch_byte(1); /* has to be after DISP */ put_smbyte(seg_reg, EA, DATA); /* MOV mem8, immed8 */ } else { put_rbyte(RM, DATA); /* MOV reg8, immed8 */ } break; case 0xC7: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (REG) { /* has to be 0 */ reason = STOP_OPCODE; IP -= 2; } if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ DATA = get_mword(IP); /* has to be after DISP */ put_smword(seg_reg, EA, DATA); /* MOV mem16, immed16 */ } else { put_rword(RM, DATA); /* MOV reg16, immed16 */ } break; /* 0xC8 - 0xC9 - Not implemented on 8086/8088 */ case 0xCA: /* RET immed16 (intersegment) */ OFF = fetch_word(); IP = pop_word(); CS = pop_word(); SP += OFF; break; case 0xCB: /* RET (intersegment) */ IP = pop_word(); CS = pop_word(); break; case 0xCC: /* INT 3 */ push_word(PSW); CLR_FLAG(IF); CLR_FLAG(TF); push_word(CS); push_word(IP); CS = get_mword(14); IP = get_mword(12); break; case 0xCD: /* INT immed8 */ OFF = fetch_byte(1); push_word(PSW); CLR_FLAG(IF); CLR_FLAG(TF); push_word(CS); push_word(IP); CS = get_mword((OFF * 4) + 2); IP = get_mword(OFF * 4); break; case 0xCE: /* INTO */ push_word(PSW); CLR_FLAG(IF); CLR_FLAG(TF); push_word(CS); push_word(IP); CS = get_mword(18); IP = get_mword(16); break; case 0xCF: /* IRET */ IP = pop_word(); CS = pop_word(); PSW = pop_word(); break; case 0xD0: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ switch(REG) { case 0: VAL = rol_byte(get_smbyte(seg_reg, EA), 1); /* ROL mem8, 1 */ break; case 1: VAL = ror_byte(get_smbyte(seg_reg, EA), 1); /* ROR mem8, 1 */ break; case 2: VAL = rcl_byte(get_smbyte(seg_reg, EA), 1); /* RCL mem8, 1 */ break; case 3: VAL = rcr_byte(get_smbyte(seg_reg, EA), 1); /* RCR mem8, 1 */ break; case 4: VAL = shl_byte(get_smbyte(seg_reg, EA), 1); /* SAL/SHL mem8, 1 */ break; case 5: VAL = shr_byte(get_smbyte(seg_reg, EA), 1); /* SHR mem8, 1 */ break; case 7: VAL = sar_byte(get_smbyte(seg_reg, EA), 1); /* SAR mem8, 1 */ break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } put_rbyte(EA, VAL); /* store result */ } else { /* RM is second register */ switch(REG) { case 0: VAL = rol_byte(get_rbyte(RM), 1); /* RCL reg8, 1 */ break; case 1: VAL = ror_byte(get_rbyte(RM), 1); /* ROR reg8, 1 */ break; case 2: VAL = rcl_byte(get_rbyte(RM), 1); /* RCL reg8, 1 */ break; case 3: VAL = rcr_byte(get_rbyte(RM), 1); /* RCR reg8, 1 */ break; case 4: VAL = shl_byte(get_rbyte(RM), 1); /* SHL/SAL reg8, 1*/ break; case 5: VAL = shr_byte(get_rbyte(RM), 1); /* SHR reg8, 1 */ break; case 7: VAL = sar_byte(get_rbyte(RM), 1); /* SAR reg8, 1 */ break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } put_rbyte(RM, VAL); /* store result */ } break; case 0xD1: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ switch(REG) { case 0: VAL = rol_word(get_smword(seg_reg, EA), 1); /* ROL mem16, 1 */ break; case 1: VAL = ror_word(get_smword(seg_reg, EA), 1); /* ROR mem16, 1 */ break; case 2: VAL = rcl_word(get_smword(seg_reg, EA), 1); /* RCL mem16, 1 */ break; case 3: VAL = rcr_word(get_smword(seg_reg, EA), 1); /* RCR mem16, 1 */ break; case 4: VAL = shl_word(get_smword(seg_reg, EA), 1); /* SAL/SHL mem16, 1 */ break; case 5: VAL = shr_word(get_smword(seg_reg, EA), 1); /* SHR mem16, 1 */ break; case 7: VAL = sar_word(get_smword(seg_reg, EA), 1); /* SAR mem16, 1 */ break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } put_rword(EA, VAL); /* store result */ } else { /* RM is second register */ switch(REG) { case 0: VAL = rol_word(get_rword(RM), 1); /* RCL reg16, 1 */ break; case 1: VAL = ror_word(get_rword(RM), 1); /* ROR reg16, 1 */ break; case 2: VAL = rcl_word(get_rword(RM), 1); /* RCL reg16, 1 */ break; case 3: VAL = rcr_word(get_rword(RM), 1); /* RCR reg16, 1 */ break; case 4: VAL = shl_word(get_rword(RM), 1); /* SHL/SAL reg16, 1 */ break; case 5: VAL = shr_word(get_rword(RM), 1); /* SHR reg16, 1 */ break; case 7: VAL = sar_word(get_rword(RM), 1); /* SAR reg16, 1 */ break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } put_rbyte(RM, VAL); /* store result */ } break; case 0xD2: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ switch(REG) { case 0: VAL = rol_byte(get_smbyte(seg_reg, EA), CL); /* ROL mem8, CL */ break; case 1: VAL = ror_byte(get_smbyte(seg_reg, EA), CL); /* ROR mem8, CL */ break; case 2: VAL = rcl_byte(get_smbyte(seg_reg, EA), CL); /* RCL mem8, CL */ break; case 3: VAL = rcr_byte(get_smbyte(seg_reg, EA), CL); /* RCR mem8, CL */ break; case 4: VAL = shl_byte(get_smbyte(seg_reg, EA), CL); /* SAL/SHL mem8, CL */ break; case 5: VAL = shr_byte(get_smbyte(seg_reg, EA), CL); /* SHR mem8, CL */ break; case 7: VAL = sar_byte(get_smbyte(seg_reg, EA), CL); /* SAR mem8, CL */ break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } put_rbyte(EA, VAL); /* store result */ } else { /* RM is second register */ switch(REG) { case 0: VAL = rol_byte(get_rbyte(RM), CL); /* RCL reg8, CL */ break; case 1: VAL = ror_byte(get_rbyte(RM), CL); /* ROR reg8, CL */ break; case 2: VAL = rcl_byte(get_rbyte(RM), CL); /* RCL reg8, CL */ break; case 3: VAL = rcr_byte(get_rbyte(RM), CL); /* RCR reg8, CL */ break; case 4: VAL = shl_byte(get_rbyte(RM), CL); /* SHL/SAL reg8, CL*/ break; case 5: VAL = shr_byte(get_rbyte(RM), CL); /* SHR reg8, CL */ break; case 7: VAL = sar_byte(get_rbyte(RM), CL); /* SAR reg8, CL */ break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } put_rbyte(RM, VAL); /* store result */ } break; case 0xD3: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ switch(REG) { case 0: VAL = rol_word(get_smword(seg_reg, EA), CL); /* ROL mem16, CL */ break; case 1: VAL = ror_word(get_smword(seg_reg, EA), CL); /* ROR mem16, CL */ break; case 2: VAL = rcl_word(get_smword(seg_reg, EA), CL); /* RCL mem16, CL */ break; case 3: VAL = rcr_word(get_smword(seg_reg, EA), CL); /* RCR mem16, CL */ break; case 4: VAL = shl_word(get_smword(seg_reg, EA), CL); /* SAL/SHL mem16, CL */ break; case 5: VAL = shr_word(get_smword(seg_reg, EA), CL); /* SHR mem16, CL */ break; case 7: VAL = sar_word(get_smword(seg_reg, EA), CL); /* SAR mem16, CL */ break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } put_rword(EA, VAL); /* store result */ } else { /* RM is second register */ switch(REG) { case 0: VAL = rol_word(get_rword(RM), CL); /* RCL reg16, CL */ break; case 1: VAL = ror_word(get_rword(RM), CL); /* ROR reg16, CL */ break; case 2: VAL = rcl_word(get_rword(RM), CL); /* RCL reg16, CL */ break; case 3: VAL = rcr_word(get_rword(RM), CL); /* RCR reg16, CL */ break; case 4: VAL = shl_word(get_rword(RM), CL); /* SHL/SAL reg16, CL */ break; case 5: VAL = shr_word(get_rword(RM), CL); /* SHR reg16, CL */ break; case 7: VAL = sar_word(get_rword(RM), CL); /* SAR reg16, CL */ break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } put_rbyte(RM, VAL); /* store result */ } break; case 0xD4: /* AAM */ VAL = fetch_word(); if (VAL != 10) { reason = STOP_OPCODE; IP -= 2; } /* note the type change here --- returning AL and AH in AX. */ AX = aam_word(AL); break; case 0xD5: /* AAD */ VAL = fetch_word(); if (VAL != 10) { reason = STOP_OPCODE; IP -= 2; } AX = aad_word(AX); break; /* 0xD6 - Not implemented on 8086/8088 */ case 0xD7: /* XLAT */ OFF = BX + (uint8)AL; AL = get_smbyte(SEG_CS, OFF); break; case 0xD8: /* ESC */ case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: case 0xDF: /* for now, do nothing, NOP for 8088 */ break; case 0xE0: /* LOOPNE label */ OFF = fetch_byte(1); OFF += (int16)IP; CX -= 1; if (CX != 0 && !GET_FLAG(ZF)) /* CX != 0 and !ZF */ IP = OFF; break; case 0xE1: /* LOOPE label */ OFF = fetch_byte(1); OFF += (int16)IP; CX -= 1; if (CX != 0 && GET_FLAG(ZF)) /* CX != 0 and ZF */ IP = OFF; break; case 0xE2: /* LOOP label */ OFF = fetch_byte(1); OFF += (int16)IP; CX -= 1; if (CX != 0) /* CX != 0 */ IP = OFF; break; case 0xE3: /* JCXZ label */ OFF = fetch_byte(1); OFF += (int16)IP; if (CX == 0) /* CX != 0 */ IP = OFF; break; case 0xE4: /* IN AL,immed8 */ OFF = fetch_byte(1); AL = dev_table[OFF].routine(0, 0); break; case 0xE5: /* IN AX,immed8 */ OFF = fetch_byte(1); AH = dev_table[OFF].routine(0, 0); AL = dev_table[OFF+1].routine(0, 0); break; case 0xE6: /* OUT AL,immed8 */ OFF = fetch_byte(1); dev_table[OFF].routine(1, AL); break; case 0xE7: /* OUT AX,immed8 */ OFF = fetch_byte(1); dev_table[OFF].routine(1, AH); dev_table[OFF+1].routine(1, AL); break; case 0xE8: /* CALL NEAR proc */ OFF = fetch_word(); push_word(IP); IP = (OFF + IP) & ADDRMASK16; break; case 0xE9: /* JMP NEAR label */ OFF = fetch_word(); IP = (OFF + IP) & ADDRMASK16; break; case 0xEA: /* JMP FAR label */ OFF = fetch_word(); SEG = fetch_word(); CS = SEG; IP = OFF; break; case 0xEB: /* JMP short-label */ OFF = fetch_byte(1); if (OFF & 0x80) /* if negative, sign extend */ OFF |= 0XFF00; IP = (IP + OFF) & ADDRMASK16; break; case 0xEC: /* IN AL,DX */ AL = dev_table[DX].routine(0, 0); break; case 0xED: /* IN AX,DX */ AH = dev_table[DX].routine(0, 0); AL = dev_table[DX+1].routine(0, 0); break; case 0xEE: /* OUT AL,DX */ dev_table[DX].routine(1, AL); break; case 0xEF: /* OUT AX,DX */ dev_table[DX].routine(1, AH); dev_table[DX+1].routine(1, AL); break; case 0xF0: /* LOCK */ /* do nothing for now */ break; /* 0xF1 - Not implemented on 8086/8088 */ case 0xF2: /* REPNE/REPNZ */ sysmode |= SYSMODE_PREFIX_REPNE; break; case 0xF3: /* REP/REPE/REPZ */ sysmode |= SYSMODE_PREFIX_REPE; break; case 0xF4: /* HLT */ reason = STOP_HALT; IP--; break; case 0xF5: /* CMC */ TOGGLE_FLAG(CF); break; case 0xF6: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ switch(REG) { case 0: /* TEST mem8, immed8 */ DATA = fetch_byte(1); test_byte(get_smbyte(seg_reg, EA), DATA); break; case 2: /* NOT mem8 */ VAL = not_byte(get_smbyte(seg_reg, EA)); put_smbyte(seg_reg, EA, VAL); /* store result */ break; case 3: /* NEG mem8 */ VAL = neg_byte(get_smbyte(seg_reg, EA)); put_smbyte(seg_reg, EA, VAL); /* store result */ break; case 4: /* MUL mem8 */ mul_byte(get_smbyte(seg_reg, EA)); break; case 5: /* IMUL mem8 */ imul_byte(get_smbyte(seg_reg, EA)); break; case 6: /* DIV mem8 */ div_byte(get_smbyte(seg_reg, EA)); break; case 7: /* IDIV mem8 */ idiv_byte(get_smbyte(seg_reg, EA)); break; default: /* bad opcode */ reason = STOP_OPCODE; IP -= 2; break; } } else { /* RM is second register */ switch(REG) { case 0: /* TEST reg8, immed8 */ DATA = fetch_byte(1); test_byte(get_rbyte(RM), DATA); break; case 2: /* NOT reg8 */ VAL = not_byte(get_rbyte(RM)); put_rbyte(RM, VAL); /* store result */ break; case 3: /* NEG reg8 */ VAL = neg_byte(get_rbyte(RM)); put_rbyte(RM, VAL); /* store result */ break; case 4: /* MUL reg8 */ mul_byte(get_rbyte(RM)); break; case 5: /* IMUL reg8 */ imul_byte(get_rbyte(RM)); break; case 6: /* DIV reg8 */ div_byte(get_rbyte(RM)); break; case 7: /* IDIV reg8 */ idiv_byte(get_rbyte(RM)); break; default: /* bad opcode */ reason = STOP_OPCODE; IP -= 2; break; } put_rbyte(RM, VAL); /* store result */ } break; case 0xF7: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ switch(REG) { case 0: /* TEST mem16, immed16 */ DATA = fetch_word(); test_word(get_smword(seg_reg, EA), DATA); break; case 2: /* NOT mem16 */ VAL = not_word(get_smword(seg_reg, EA)); put_smword(seg_reg, EA, VAL); /* store result */ break; case 3: /* NEG mem16 */ VAL = neg_word(get_smword(seg_reg, EA)); put_smword(seg_reg, EA, VAL); /* store result */ break; case 4: /* MUL mem16 */ mul_word(get_smword(seg_reg, EA)); break; case 5: /* IMUL mem16 */ imul_word(get_smword(seg_reg, EA)); break; case 6: /* DIV mem16 */ div_word(get_smword(seg_reg, EA)); break; case 7: /* IDIV mem16 */ idiv_word(get_smword(seg_reg, EA)); break; default: /* bad opcode */ reason = STOP_OPCODE; IP -= 2; break; } } else { /* RM is second register */ switch(REG) { case 0: /* TEST reg16, immed16 */ DATA = fetch_word(); test_word(get_rword(RM), DATA); break; case 2: /* NOT reg16 */ VAL = not_word(get_rword(RM)); put_rword(RM, VAL); /* store result */ break; case 3: /* NEG reg16 */ VAL = neg_word(get_rword(RM)); put_rword(RM, VAL); /* store result */ break; case 4: /* MUL reg16 */ mul_word(get_rword(RM)); break; case 5: /* IMUL reg16 */ imul_word(get_rword(RM)); break; case 6: /* DIV reg16 */ div_word(get_rword(RM)); break; case 7: /* IDIV reg16 */ idiv_word(get_rword(RM)); break; default: /* bad opcode */ reason = STOP_OPCODE; IP -= 2; break; } put_rbyte(RM, VAL); /* store result */ } break; case 0xF8: /* CLC */ CLR_FLAG(CF); break; case 0xF9: /* STC */ SET_FLAG(CF); break; case 0xFA: /* CLI */ CLR_FLAG(IF); break; case 0xFB: /* STI */ SET_FLAG(IF); break; case 0xFC: /* CLD */ CLR_FLAG(DF); break; case 0xFD: /* STD */ SET_FLAG(DF); break; case 0xFE: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ switch(REG) { case 0: /* INC mem16 */ VAL = inc_byte(get_smbyte(seg_reg, EA)); /* do operation */ put_smbyte(seg_reg, EA, VAL); /* store result */ break; case 1: /* DEC mem16 */ VAL = dec_byte(get_smbyte(seg_reg, EA)); /* do operation */ put_smbyte(seg_reg, EA, VAL); /* store result */ break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } } else { /* RM is second register */ switch(REG) { case 0: VAL = inc_byte(get_rbyte(RM)); /* do operation */ put_rbyte(RM, VAL); /* store result */ break; case 1: VAL = dec_byte(get_rbyte(RM)); /* do operation */ put_rbyte(RM, VAL); /* store result */ break; default: /* bad opcodes */ reason = STOP_OPCODE; IP -= 2; break; } put_rbyte(RM, VAL); /* store result */ } break; case 0xFF: MRR = fetch_byte(1); get_mrr_dec(MRR, &MOD, ®, &RM); if (MOD != 0x3) { /* based, indexed, or based indexed addressing */ EA = get_ea(MRR); /* get effective address */ switch(REG) { case 0: /* INC mem16 */ VAL = inc_word(get_smword(seg_reg, EA)); /* do operation */ put_smword(seg_reg, EA, VAL); /* store result */ break; case 1: /* DEC mem16 */ VAL = dec_word(get_smword(seg_reg, EA)); /* do operation */ put_smword(seg_reg, EA, VAL); /* store result */ break; case 2: /* CALL NEAR mem16 */ OFF = get_smword(SEG_CS, EA); /* do operation */ push_word(IP); IP = OFF; break; case 3: /* CALL FAR mem16 */ OFF = get_smword(SEG_CS, EA); /* do operation */ SEG = get_smword(SEG_CS, EA + 2); push_word(CS); CS = SEG; push_word(IP); IP = OFF; break; case 4: /* JMP NEAR mem16 */ OFF = get_smword(SEG_CS, EA); /* do operation */ IP = OFF; break; case 5: /* JMP FAR mem16 */ OFF = get_smword(SEG_CS, EA); /* do operation */ SEG = get_smword(SEG_CS, EA + 2); CS = SEG; IP = OFF; break; case 6: /* PUSH mem16 */ VAL = get_smword(seg_reg, EA); /* do operation */ push_word(VAL); break; case 7: /* bad opcode */ reason = STOP_OPCODE; IP -= 2; break; } } else { /* RM is second register */ switch(REG) { case 2: /* CALL NEAR reg16 */ OFF = get_rword(RM); /* do operation */ push_word(IP); IP = OFF; break; case 4: /* JMP NEAR reg16 */ OFF = get_rword(RM); /* do operation */ IP = OFF; break; default: /* bad opcode */ reason = STOP_OPCODE; IP -= 2; break; } put_rbyte(RM, VAL); /* store result */ } break; default: // if (i8088_unit.flags & UNIT_OPSTOP) { reason = STOP_OPCODE; IP--; // } break; } /* not segment override */ if ((IR == 0x26) || (IR == 0x2E) || (IR == 0x36) || (IR == 0x3E)) { seg_ovr = SEG_NONE; /* clear segment override */ sysmode &= 0x0000001E; /* clear flags */ sysmode |= 0x00000001; } } /* Simulation halted */ saved_PC = IP; return reason; } /* emulation subfunctions */ int32 sign_ext(int32 val) { int32 res; res = val; if (val & 0x80) res |= 0xFF00; return res; } int32 fetch_byte(int32 flag) { uint8 val; val = get_smbyte(SEG_CS, IP) & 0xFF; /* fetch byte */ if (i8088_dev.dctrl & DEBUG_asm) { /* display source code */ switch (flag) { case 0: /* opcode fetch */ // sim_printf("%04X:%04X %s", CS, IP, opcode[val]); sim_printf("%04X:%04X %02X", CS, IP, val); break; case 1: /* byte operand fetch */ sim_printf(" %02X", val); break; } } IP = INC_IP1; /* increment IP */ return val; } int32 fetch_word(void) { uint16 val; val = get_smbyte(SEG_CS, IP) & 0xFF; /* fetch low byte */ val |= get_smbyte(SEG_CS, IP + 1) << 8; /* fetch high byte */ if (i8088_dev.dctrl & DEBUG_asm) // sim_printf("0%04XH", val); sim_printf(" %04X", val); IP = INC_IP2; /* increment IP */ return val; } /* calculate parity on a 8- or 16-bit value */ int32 parity(int32 val) { int32 bc = 0; if (val & 0x0001) bc++; if (val & 0x0002) bc++; if (val & 0x0004) bc++; if (val & 0x0008) bc++; if (val & 0x0010) bc++; if (val & 0x0020) bc++; if (val & 0x0040) bc++; if (val & 0x0080) bc++; if (val & 0x0100) bc++; if (val & 0x0200) bc++; if (val & 0x0400) bc++; if (val & 0x0800) bc++; if (val & 0x1000) bc++; if (val & 0x2000) bc++; if (val & 0x4000) bc++; if (val & 0x8000) bc++; return bc & 1; } void i86_intr_raise(uint8 num) { /* do nothing for now */ } /* return byte register */ uint32 get_rbyte(uint32 reg) { uint32 val; switch(reg) { case 0: val = AL; break; case 1: val = CL; break; case 2: val = DL; break; case 3: val = BL; break; case 4: val = AH; break; case 5: val = CH; break; case 6: val = DH; break; case 7: val = BH; break; } return val; } /* return word register - added segment registers as 8-11 */ uint32 get_rword(uint32 reg) { uint32 val; switch(reg) { case 0: val = AX; break; case 1: val = CX; break; case 2: val = DX; break; case 3: val = BX; break; case 4: val = SP; break; case 5: val = BP; break; case 6: val = SI; break; case 7: val = DI; break; case 8: val = CS; break; case 9: val = DS; break; case 10: val = ES; break; case 11: val = SS; break; } return val; } /* set byte register */ void put_rbyte(uint32 reg, uint32 val) { val &= 0xFF; /* force byte */ switch(reg){ case 0: AL = val; break; case 1: CL = val; break; case 2: DL = val; break; case 3: BL = val; break; case 4: AH = val; break; case 5: CH = val; break; case 6: DH = val; break; case 7: BH = val; break; } } /* set word register */ void put_rword(uint32 reg, uint32 val) { val &= 0xFFFF; /* force word */ switch(reg){ case 0: AX = val; break; case 1: CX = val; break; case 2: DX = val; break; case 3: BX = val; break; case 4: SP = val; break; case 5: BP = val; break; case 6: SI = val; break; case 7: DI = val; break; } } /* set seg_reg as required for EA */ void set_segreg(uint32 reg) { if (seg_ovr) seg_reg = seg_ovr; else seg_ovr = reg; } /* return effective address from mrr - also set seg_reg */ uint32 get_ea(uint32 mrr) { uint32 MOD, REG, RM, DISP, EA; get_mrr_dec(mrr, &MOD, ®, &RM); switch(MOD) { case 0: /* DISP = 0 */ DISP = 0; switch(RM) { case 0: EA = BX + SI; set_segreg(SEG_DS); break; case 1: EA = BX + DI; set_segreg(SEG_DS); break; case 2: EA = BP + SI; set_segreg(SEG_SS); break; case 3: EA = BP + DI; set_segreg(SEG_SS); break; case 4: EA = SI; set_segreg(SEG_DS); break; case 5: EA = DI; set_segreg(SEG_ES); break; case 6: DISP = fetch_word(); EA = DISP; set_segreg(SEG_DS); break; case 7: EA = BX; set_segreg(SEG_DS); break; } break; case 1: /* DISP is byte */ DISP = fetch_byte(1); switch(RM) { case 0: EA = BX + SI + DISP; set_segreg(SEG_DS); break; case 1: EA = BX + DI + DISP; set_segreg(SEG_DS); break; case 2: EA = BP + SI + DISP; set_segreg(SEG_SS); break; case 3: EA = BP + DI + DISP; set_segreg(SEG_SS); break; case 4: EA = SI + DISP; set_segreg(SEG_DS); break; case 5: EA = DI + DISP; set_segreg(SEG_ES); break; case 6: EA = BP + DISP; set_segreg(SEG_SS); break; case 7: EA = BX + DISP; set_segreg(SEG_DS); break; } break; case 2: /* DISP is word */ DISP = fetch_word(); switch(RM) { case 0: EA = BX + SI + DISP; set_segreg(SEG_DS); break; case 1: EA = BX + DI + DISP; set_segreg(SEG_DS); break; case 2: EA = BP + SI + DISP; set_segreg(SEG_SS); break; case 3: EA = BP + DI + DISP; set_segreg(SEG_SS); break; case 4: EA = SI + DISP; set_segreg(SEG_DS); break; case 5: EA = DI + DISP; set_segreg(SEG_ES); break; case 6: EA = BP + DISP; set_segreg(SEG_SS); break; case 7: EA = BX + DISP; set_segreg(SEG_SS); break; } break; case 3: /* RM is register field */ break; } if (i8088_dev.dctrl & DEBUG_level1) sim_printf("get_ea: MRR=%02X MOD=%02X REG=%02X R/M=%02X DISP=%04X EA=%04X\n", mrr, MOD, REG, RM, DISP, EA); return EA; } /* return mod, reg and rm field from mrr */ void get_mrr_dec(uint32 mrr, uint32 *mod, uint32 *reg, uint32 *rm) { *mod = (mrr >> 6) & 0x3; *reg = (mrr >> 3) & 0x7; *rm = mrr & 0x7; } /* Most of the primitive algorythms were pulled from the GDE Dos/IP Emulator by Jim Hudgens */ /* aad primitive */ uint8 aad_word(uint16 d) { uint16 VAL; uint8 HI, LOW; HI = (d >> 8) & 0xFF; LOW = d & 0xFF; VAL = LOW + 10 * HI; CONDITIONAL_SET_FLAG(VAL & 0x80, SF); CONDITIONAL_SET_FLAG(VAL == 0, ZF); CONDITIONAL_SET_FLAG(parity(VAL & 0xFF), PF); return (uint8) VAL; } /* aam primitive */ uint16 aam_word(uint8 d) { uint16 VAL, HI; HI = d / 10; VAL = d % 10; VAL |= (HI << 8); CONDITIONAL_SET_FLAG(VAL & 0x80, SF); CONDITIONAL_SET_FLAG(VAL == 0, ZF); CONDITIONAL_SET_FLAG(parity(VAL & 0xFF), PF); return VAL; } /* add with carry byte primitive */ uint8 adc_byte(uint8 d, uint8 s) { register uint16 res; register uint16 cc; if (GET_FLAG(CF)) res = 1 + d + s; else res = d + s; /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x0100, CF); CONDITIONAL_SET_FLAG((res & 0xff) == 0, ZF); CONDITIONAL_SET_FLAG(res & 0x80, SF); CONDITIONAL_SET_FLAG(parity(res & 0xff), PF); /* calculate the carry chain SEE NOTE AT TOP.*/ cc = (s & d) | ((~res) & (s | d)); /* set the flags based on the carry chain */ CONDITIONAL_SET_FLAG(xor_3_tab[(cc >> 6) & 0x3], OF); CONDITIONAL_SET_FLAG(cc & 0x08, AF); return (uint8) res; } /* add with carry word primitive */ uint16 adc_word(uint16 d, uint16 s) { register uint32 res; register uint32 cc; if (GET_FLAG(CF)) res = 1 + d + s; else res = d + s; /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x10000, CF); CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); /* calculate the carry chain SEE NOTE AT TOP.*/ cc = (s & d) | ((~res) & (s | d)); /* set the flags based on the carry chain */ CONDITIONAL_SET_FLAG(xor_3_tab[(cc >> 14) & 0x3], OF); CONDITIONAL_SET_FLAG(cc & 0x08, AF); return res; } /* add byte primitive */ uint8 add_byte(uint8 d, uint8 s) { register uint16 res; register uint16 cc; res = d + s; /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x0100, CF); CONDITIONAL_SET_FLAG((res & 0xFF) == 0, ZF); CONDITIONAL_SET_FLAG(res & 0x80, SF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); /* calculate the carry chain SEE NOTE AT TOP.*/ cc = (s & d) | ((~res) & (s | d)); /* set the flags based on the carry chain */ CONDITIONAL_SET_FLAG(xor_3_tab[(cc >> 6) & 0x3], OF); CONDITIONAL_SET_FLAG(cc & 0x08, AF); return (uint8) res; } /* add word primitive */ uint16 add_word(uint16 d, uint16 s) { register uint32 res; register uint32 cc; res = d + s; /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x10000, CF); CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG(parity(res & 0xff), PF); /* calculate the carry chain SEE NOTE AT TOP.*/ cc = (s & d) | ((~res) & (s | d)); /* set the flags based on the carry chain */ CONDITIONAL_SET_FLAG(xor_3_tab[(cc >> 14) & 0x3], OF); CONDITIONAL_SET_FLAG(cc & 0x08, AF); return res; } /* and byte primitive */ uint8 and_byte(uint8 d, uint8 s) { register uint8 res; res = d & s; /* clear flags */ CLR_FLAG(OF); CLR_FLAG(CF); /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x80, SF); CONDITIONAL_SET_FLAG(res == 0, ZF); CONDITIONAL_SET_FLAG(parity(res), PF); return res; } /* and word primitive */ uint16 and_word(uint16 d, uint16 s) { register uint16 res; res = d & s; /* clear flags */ CLR_FLAG(OF); CLR_FLAG(CF); /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG(res == 0, ZF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); return res; } /* cmp byte primitive */ uint8 cmp_byte(uint8 d, uint8 s) { register uint32 res; register uint32 bc; res = d - s; /* clear flags */ CLR_FLAG(CF); /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x80, SF); CONDITIONAL_SET_FLAG((res & 0xFF)==0, ZF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); /* calculate the borrow chain. See note at top */ bc= (res&(~d|s))|(~d&s); /* set flags based on borrow chain */ CONDITIONAL_SET_FLAG(bc & 0x80, CF); CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 6) & 0x3], OF); CONDITIONAL_SET_FLAG(bc & 0x8, AF); return d; /* long story why this is needed. Look at opcode 0x80 in ops.c, for an idea why this is necessary.*/ } /* cmp word primitive */ uint16 cmp_word(uint16 d, uint16 s) { register uint32 res; register uint32 bc; res = d - s; /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); /* calculate the borrow chain. See note at top */ bc = (res & (~d | s)) | (~d &s); /* set flags based on borrow chain */ CONDITIONAL_SET_FLAG(bc & 0x8000, CF); CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 14) & 0x3], OF); CONDITIONAL_SET_FLAG(bc & 0x8, AF); return d; /* long story why this is needed. Look at opcode 0x80 in ops.c, for an idea why this is necessary.*/ } /* dec byte primitive */ uint8 dec_byte(uint8 d) { register uint32 res; register uint32 bc; res = d - 1; /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x80, SF); CONDITIONAL_SET_FLAG((res & 0xff)==0, ZF); CONDITIONAL_SET_FLAG(parity(res & 0xff), PF); /* calculate the borrow chain. See note at top */ /* based on sub_byte, uses s=1. */ bc = (res & (~d | 1)) | (~d & 1); /* carry flag unchanged */ /* set flags based on borrow chain */ CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 6) & 0x3], OF); CONDITIONAL_SET_FLAG(bc & 0x8, AF); return res; } /* dec word primitive */ uint16 dec_word(uint16 d) { register uint32 res; register uint32 bc; res = d - 1; /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG((res & 0xffff) == 0, ZF); CONDITIONAL_SET_FLAG(parity(res & 0xff), PF); /* calculate the borrow chain. See note at top */ /* based on the sub_byte routine, with s==1 */ bc = (res & (~d | 1)) | (~d & 1); /* carry flag unchanged */ /* set flags based on borrow chain */ CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 14) & 0x3], OF); CONDITIONAL_SET_FLAG(bc & 0x8, AF); return res; } /* div byte primitive */ void div_byte(uint8 s) { uint32 dvd, dvs, div, mod; dvs = s; dvd = AX; if (s == 0) { i86_intr_raise(0); return; } div = dvd / dvs; mod = dvd % dvs; if (abs(div) > 0xFF) { i86_intr_raise(0); return; } /* Undef --- Can't hurt */ CLR_FLAG(SF); CONDITIONAL_SET_FLAG(div == 0, ZF); AL = (uint8)div; AH = (uint8)mod; } /* div word primitive */ void div_word(uint16 s) { uint32 dvd, dvs, div, mod; dvd = DX; dvd = (dvd << 16) | AX; dvs = s; if (dvs == 0) { i86_intr_raise(0); return; } div = dvd / dvs; mod = dvd % dvs; if (abs(div) > 0xFFFF) { i86_intr_raise(0); return; } /* Undef --- Can't hurt */ CLR_FLAG(SF); CONDITIONAL_SET_FLAG(div == 0, ZF); AX = div; DX = mod; } /* idiv byte primitive */ void idiv_byte(uint8 s) { int32 dvd, div, mod; dvd = (int16)AX; if (s == 0) { i86_intr_raise(0); return; } div = dvd / (int8)s; mod = dvd % (int8)s; if (abs(div) > 0x7F) { i86_intr_raise(0); return; } /* Undef --- Can't hurt */ CONDITIONAL_SET_FLAG(div & 0x80, SF); CONDITIONAL_SET_FLAG(div == 0, ZF); AL = (int8)div; AH = (int8)mod; } /* idiv word primitive */ void idiv_word(uint16 s) { int32 dvd, dvs, div, mod; dvd = DX; dvd = (dvd << 16) | AX; if (s == 0) { i86_intr_raise(0); return; } dvs = (int16)s; div = dvd / dvs; mod = dvd % dvs; if (abs(div) > 0x7FFF) { i86_intr_raise(0); return; } /* Undef --- Can't hurt */ CONDITIONAL_SET_FLAG(div & 0x8000, SF); CONDITIONAL_SET_FLAG(div == 0, ZF); AX = div; DX = mod; } /* imul byte primitive */ void imul_byte(uint8 s) { int16 res; res = (int8)AL * (int8)s; AX = res; /* Undef --- Can't hurt */ CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG(res == 0, ZF); if ( AH == 0 || AH == 0xFF) { CLR_FLAG(CF); CLR_FLAG(OF); } else { SET_FLAG(CF); SET_FLAG(OF); } } /* imul word primitive */ void imul_word(uint16 s) { int32 res; res = (int16)AX * (int16)s; AX = res & 0xFFFF; DX = (res >> 16) & 0xFFFF; /* Undef --- Can't hurt */ CONDITIONAL_SET_FLAG(res & 0x80000000, SF); CONDITIONAL_SET_FLAG(res == 0, ZF); if (DX == 0 || DX == 0xFFFF) { CLR_FLAG(CF); CLR_FLAG(OF); } else { SET_FLAG(CF); SET_FLAG(OF); } } /* inc byte primitive */ uint8 inc_byte(uint8 d) { register uint32 res; register uint32 cc; res = d + 1; /* set the flags based on the result */ CONDITIONAL_SET_FLAG((res & 0xFF) == 0, ZF); CONDITIONAL_SET_FLAG(res & 0x80, SF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); /* calculate the carry chain SEE NOTE AT TOP.*/ cc = ((1 & d) | (~res)) & (1 | d); /* set the flags based on the carry chain */ CONDITIONAL_SET_FLAG(xor_3_tab[(cc >> 6) & 0x3], OF); CONDITIONAL_SET_FLAG(cc & 0x8, AF); return res; } /* inc word primitive */ uint16 inc_word(uint16 d) { register uint32 res; register uint32 cc; res = d + 1; /* set the flags based on the result */ CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG(parity(res & 0xff), PF); /* calculate the carry chain SEE NOTE AT TOP.*/ cc = (1 & d) | ((~res) & (1 | d)); /* set the flags based on the carry chain */ CONDITIONAL_SET_FLAG(xor_3_tab[(cc >> 14) & 0x3], OF); CONDITIONAL_SET_FLAG(cc & 0x8, AF); return res ; } /* mul byte primitive */ void mul_byte(uint8 s) { uint16 res; res = AL * s; AX = res; /* Undef --- Can't hurt */ CLR_FLAG(SF); CONDITIONAL_SET_FLAG(res == 0, ZF); if (AH == 0) { CLR_FLAG(CF); CLR_FLAG(OF); } else { SET_FLAG(CF); SET_FLAG(OF); } } /* mul word primitive */ void mul_word(uint16 s) { uint32 res; res = AX * s; /* Undef --- Can't hurt */ CLR_FLAG(SF); CONDITIONAL_SET_FLAG(res == 0, ZF); AX = res & 0xFFFF; DX = (res >> 16) & 0xFFFF; if (DX == 0) { CLR_FLAG(CF); CLR_FLAG(OF); } else { SET_FLAG(CF); SET_FLAG(OF); } } /* neg byte primitive */ uint8 neg_byte(uint8 s) { register uint8 res; register uint8 bc; CONDITIONAL_SET_FLAG(s != 0, CF); res = -s; CONDITIONAL_SET_FLAG((res & 0xff) == 0, ZF); CONDITIONAL_SET_FLAG(res & 0x80, SF); CONDITIONAL_SET_FLAG(parity(res), PF); /* calculate the borrow chain --- modified such that d=0. */ bc= res | s; CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 6) & 0x3], OF); CONDITIONAL_SET_FLAG(bc & 0x8, AF); return res; } /* neg word primitive */ uint16 neg_word(uint16 s) { register uint16 res; register uint16 bc; CONDITIONAL_SET_FLAG(s != 0, CF); res = -s; CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); /* calculate the borrow chain --- modified such that d=0 */ bc= res | s; CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 6) & 0x3], OF); CONDITIONAL_SET_FLAG(bc & 0x8, AF); return res; } /* not byte primitive */ uint8 not_byte(uint8 s) { return ~s; } /* not word primitive */ uint16 not_word(uint16 s) { return ~s; } /* or byte primitive */ uint8 or_byte(uint8 d, uint8 s) { register uint8 res; res = d | s; /* clear flags */ CLR_FLAG(OF); CLR_FLAG(CF); /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x80, SF); CONDITIONAL_SET_FLAG(res == 0, ZF); CONDITIONAL_SET_FLAG(parity(res), PF); return res; } /* or word primitive */ uint16 or_word(uint16 d, uint16 s) { register uint16 res; res = d | s; /* clear flags */ CLR_FLAG(OF); CLR_FLAG(CF); /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG(res == 0, ZF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); return res; } /* push word primitive */ void push_word(uint16 val) { SP--; put_smbyte(SS, SP, val >> 8); SP--; put_smbyte(SS, SP, val & 0xFF); } /* pop word primitive */ uint16 pop_word(void) { register uint16 res; res = get_smbyte(SS, SP); SP++; res |= (get_smbyte(SS, SP) << 8); SP++; return res; } /* rcl byte primitive */ uint8 rcl_byte(uint8 d, uint8 s) { register uint32 res, cnt, mask, cf; res = d; if ((cnt = s % 9)) { cf = (d >> (8-cnt)) & 0x1; res = (d << cnt) & 0xFF; mask = (1<<(cnt-1)) - 1; res |= (d >> (9-cnt)) & mask; if (GET_FLAG(CF)) res |= 1 << (cnt-1); CONDITIONAL_SET_FLAG(cf, CF); CONDITIONAL_SET_FLAG(cnt == 1 && xor_3_tab[cf + ((res >> 6) & 0x2)], OF); } return res & 0xFF; } /* rcl word primitive */ uint16 rcl_word(uint16 d, uint16 s) { register uint32 res, cnt, mask, cf; res = d; if ((cnt = s % 17)) { cf = (d >> (16-cnt)) & 0x1; res = (d << cnt) & 0xFFFF; mask = (1<<(cnt-1)) - 1; res |= (d >> (17-cnt)) & mask; if (GET_FLAG(CF)) res |= 1 << (cnt-1); CONDITIONAL_SET_FLAG(cf, CF); CONDITIONAL_SET_FLAG(cnt == 1 && xor_3_tab[cf + ((res >> 14) & 0x2)], OF); } return res & 0xFFFF; } /* rcr byte primitive */ uint8 rcr_byte(uint8 d, uint8 s) { uint8 res, cnt; uint8 mask, cf, ocf = 0; res = d; if ((cnt = s % 9)) { if (cnt == 1) { cf = d & 0x1; ocf = GET_FLAG(CF) != 0; } else cf = (d >> (cnt - 1)) & 0x1; mask = (1 <<( 8 - cnt)) - 1; res = (d >> cnt) & mask; res |= (d << (9-cnt)); if (GET_FLAG(CF)) res |= 1 << (8 - cnt); CONDITIONAL_SET_FLAG(cf, CF); if (cnt == 1) CONDITIONAL_SET_FLAG(xor_3_tab[ocf + ((d >> 6) & 0x2)], OF); } return res; } /* rcr word primitive */ uint16 rcr_word(uint16 d, uint16 s) { uint16 res, cnt; uint16 mask, cf, ocf = 0; res = d; if ((cnt = s % 17)) { if (cnt == 1) { cf = d & 0x1; ocf = GET_FLAG(CF) != 0; } else cf = (d >> (cnt-1)) & 0x1; mask = (1 <<( 16 - cnt)) - 1; res = (d >> cnt) & mask; res |= (d << (17 - cnt)); if (GET_FLAG(CF)) res |= 1 << (16 - cnt); CONDITIONAL_SET_FLAG(cf, CF); if (cnt == 1) CONDITIONAL_SET_FLAG(xor_3_tab[ocf + ((d >> 14) & 0x2)], OF); } return res; } /* rol byte primitive */ uint8 rol_byte(uint8 d, uint8 s) { register uint32 res, cnt, mask; res =d; if ((cnt = s % 8)) { res = (d << cnt); mask = (1 << cnt) - 1; res |= (d >> (8-cnt)) & mask; CONDITIONAL_SET_FLAG(res & 0x1, CF); CONDITIONAL_SET_FLAG(cnt == 1 && xor_3_tab[(res & 0x1) + ((res >> 6) & 0x2)], OF); } return res & 0xFF; } /* rol word primitive */ uint16 rol_word(uint16 d, uint16 s) { register uint32 res, cnt, mask; res = d; if ((cnt = s % 16)) { res = (d << cnt); mask = (1 << cnt) - 1; res |= (d >> (16 - cnt)) & mask; CONDITIONAL_SET_FLAG(res & 0x1, CF); CONDITIONAL_SET_FLAG(cnt == 1 && xor_3_tab[(res & 0x1) + ((res >> 14) & 0x2)], OF); } return res&0xFFFF; } /* ror byte primitive */ uint8 ror_byte(uint8 d, uint8 s) { register uint32 res, cnt, mask; res = d; if ((cnt = s % 8)) { res = (d << (8-cnt)); mask = (1 << (8-cnt)) - 1; res |= (d >> (cnt)) & mask; CONDITIONAL_SET_FLAG(res & 0x80, CF); CONDITIONAL_SET_FLAG(cnt == 1 && xor_3_tab[(res >> 6) & 0x3], OF); } return res & 0xFF; } /* ror word primitive */ uint16 ror_word(uint16 d, uint16 s) { register uint32 res, cnt, mask; res = d; if ((cnt = s % 16)) { res = (d << (16-cnt)); mask = (1 << (16-cnt)) - 1; res |= (d >> (cnt)) & mask; CONDITIONAL_SET_FLAG(res & 0x8000, CF); CONDITIONAL_SET_FLAG(cnt == 1 && xor_3_tab[(res >> 14) & 0x3], OF); } return res & 0xFFFF; } /* shl byte primitive */ uint8 shl_byte(uint8 d, uint8 s) { uint32 cnt, res, cf; if (s < 8) { cnt = s % 8; if (cnt > 0) { res = d << cnt; cf = d & (1 << (8 - cnt)); CONDITIONAL_SET_FLAG(cf, CF); CONDITIONAL_SET_FLAG((res & 0xFF)==0, ZF); CONDITIONAL_SET_FLAG(res & 0x80, SF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); } else res = (uint8) d; if (cnt == 1) CONDITIONAL_SET_FLAG((((res & 0x80) == 0x80) ^ (GET_FLAG( CF) != 0)), OF); else CLR_FLAG(OF); } else { res = 0; CONDITIONAL_SET_FLAG((s == 8) && (d & 1), CF); CLR_FLAG(OF); CLR_FLAG(SF); CLR_FLAG(PF); SET_FLAG(ZF); } return res & 0xFF; } /* shl word primitive */ uint16 shl_word(uint16 d, uint16 s) { uint32 cnt, res, cf; if (s < 16) { cnt = s % 16; if (cnt > 0) { res = d << cnt; cf = d & (1<<(16-cnt)); CONDITIONAL_SET_FLAG(cf, CF); CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); } else res = (uint16) d; if (cnt == 1) CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^ (GET_FLAG(CF) != 0)), OF); else CLR_FLAG(OF); } else { res = 0; CONDITIONAL_SET_FLAG((s == 16) && (d & 1), CF); CLR_FLAG(OF); SET_FLAG(ZF); CLR_FLAG(SF); CLR_FLAG(PF); } return res & 0xFFFF; } /* shr byte primitive */ uint8 shr_byte(uint8 d, uint8 s) { uint32 cnt, res, cf, mask; if (s < 8) { cnt = s % 8; if (cnt > 0) { mask = (1 << (8 - cnt)) - 1; cf = d & (1 << (cnt - 1)); res = (d >> cnt) & mask; CONDITIONAL_SET_FLAG(cf, CF); CONDITIONAL_SET_FLAG((res & 0xFF) == 0, ZF); CONDITIONAL_SET_FLAG(res & 0x80, SF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); } else res = (uint8) d; if (cnt == 1) CONDITIONAL_SET_FLAG(xor_3_tab[(res >> 6) & 0x3], OF); else CLR_FLAG(OF); } else { res = 0; CONDITIONAL_SET_FLAG((s == 8) && (d & 0x80), CF); CLR_FLAG(OF); SET_FLAG(ZF); CLR_FLAG(SF); CLR_FLAG(PF); } return res & 0xFF; } /* shr word primitive */ uint16 shr_word(uint16 d, uint16 s) { uint32 cnt, res, cf, mask; res = d; if (s < 16) { cnt = s % 16; if (cnt > 0) { mask = (1 << (16 - cnt)) - 1; cf = d & (1 << (cnt - 1)); res = (d >> cnt) & mask; CONDITIONAL_SET_FLAG(cf, CF); CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); } else res = d; if (cnt == 1) CONDITIONAL_SET_FLAG(xor_3_tab[(res >> 14) & 0x3], OF); else CLR_FLAG(OF); } else { res = 0; CONDITIONAL_SET_FLAG((s == 16) && (d & 0x8000), CF); CLR_FLAG(OF); SET_FLAG(ZF); CLR_FLAG(SF); CLR_FLAG(PF); } return res & 0xFFFF; } /* sar byte primitive */ uint8 sar_byte(uint8 d, uint8 s) { uint32 cnt, res, cf, mask, sf; res = d; sf = d & 0x80; cnt = s % 8; if (cnt > 0 && cnt < 8) { mask = (1 << (8 - cnt)) - 1; cf = d & (1 << (cnt -1 )); res = (d >> cnt) & mask; CONDITIONAL_SET_FLAG(cf, CF); if (sf) res |= ~mask; CONDITIONAL_SET_FLAG((res & 0xFF)==0, ZF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); CONDITIONAL_SET_FLAG(res & 0x80, SF); } else if (cnt >= 8) { if (sf) { res = 0xFF; SET_FLAG(CF); CLR_FLAG(ZF); SET_FLAG(SF); SET_FLAG(PF); } else { res = 0; CLR_FLAG(CF); SET_FLAG(ZF); CLR_FLAG(SF); CLR_FLAG(PF); } } return res & 0xFF; } /* sar word primitive */ uint16 sar_word(uint16 d, uint16 s) { uint32 cnt, res, cf, mask, sf; sf = d & 0x8000; cnt = s % 16; res = d; if (cnt > 0 && cnt < 16) { mask = (1 << (16 - cnt)) - 1; cf = d & (1 << (cnt - 1)); res = (d >> cnt) & mask; CONDITIONAL_SET_FLAG(cf, CF); if (sf) res |= ~mask; CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); } else if (cnt >= 16) { if (sf) { res = 0xFFFF; SET_FLAG(CF); CLR_FLAG(ZF); SET_FLAG(SF); SET_FLAG(PF); } else { res = 0; CLR_FLAG(CF); SET_FLAG(ZF); CLR_FLAG(SF); CLR_FLAG(PF); } } return res & 0xFFFF; } /* sbb byte primitive */ uint8 sbb_byte(uint8 d, uint8 s) { register uint32 res; register uint32 bc; if (GET_FLAG(CF)) res = d - s - 1; else res = d - s; /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x80, SF); CONDITIONAL_SET_FLAG((res & 0xFF) == 0, ZF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); /* calculate the borrow chain. See note at top */ bc= (res&(~d|s))|(~d&s); /* set flags based on borrow chain */ CONDITIONAL_SET_FLAG(bc & 0x80, CF); CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 6) & 0x3], OF); CONDITIONAL_SET_FLAG(bc & 0x8, AF); // return res & 0x0FF; return (uint8) res; } /* sbb word primitive */ uint16 sbb_word(uint16 d, uint16 s) { register uint32 res; register uint32 bc; if (GET_FLAG(CF)) res = d - s - 1; else res = d - s; /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG((res & 0xFFFF) == 0, ZF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); /* calculate the borrow chain. See note at top */ bc= (res&(~d|s))|(~d&s); /* set flags based on borrow chain */ CONDITIONAL_SET_FLAG(bc & 0x8000, CF); CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 14) & 0x3], OF); CONDITIONAL_SET_FLAG(bc & 0x8, AF); // return res & 0xFFFF; return (uint16) res; } /* sub byte primitive */ uint8 sub_byte(uint8 d, uint8 s) { register uint32 res; register uint32 bc; res = d - s; /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x80, SF); CONDITIONAL_SET_FLAG((res & 0xFF) == 0, ZF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); /* calculate the borrow chain. See note at top */ bc= (res&(~d|s))|(~d&s); /* set flags based on borrow chain */ CONDITIONAL_SET_FLAG(bc & 0x80, CF); CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 6) & 0x3], OF); CONDITIONAL_SET_FLAG(bc & 0x8, AF); // return res & 0xff; return (uint8) res; } /* sub word primitive */ uint16 sub_word(uint16 d, uint16 s) { register uint32 res; register uint32 bc; res = d - s; /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res &0x8000, SF); CONDITIONAL_SET_FLAG((res &0xFFFF) == 0, ZF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); /* calculate the borrow chain. See note at top */ bc= (res&(~d|s))|(~d&s); /* set flags based on borrow chain */ CONDITIONAL_SET_FLAG(bc & 0x8000, CF); CONDITIONAL_SET_FLAG(xor_3_tab[(bc >> 14) & 0x3], OF); CONDITIONAL_SET_FLAG(bc & 0x8, AF); // return res & 0xffff; return (uint16) res; } /* test byte primitive */ void test_byte(uint8 d, uint8 s) { register uint32 res; res = d & s; CLR_FLAG(OF); CONDITIONAL_SET_FLAG(res & 0x80, SF); CONDITIONAL_SET_FLAG(res == 0, ZF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); /* AF == dont care*/ CLR_FLAG(CF); } /* test word primitive */ void test_word(uint16 d, uint16 s) { register uint32 res; res = d & s; CLR_FLAG(OF); CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG(res == 0, ZF); CONDITIONAL_SET_FLAG(parity(res & 0xff), PF); /* AF == dont care*/ CLR_FLAG(CF); } /* xor byte primitive */ uint8 xor_byte(uint8 d, uint8 s) { register uint8 res; res = d ^ s; /* clear flags */ CLR_FLAG(OF); CLR_FLAG(CF); /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x80, SF); CONDITIONAL_SET_FLAG(res == 0, ZF); CONDITIONAL_SET_FLAG(parity(res), PF); return res; } /* xor word primitive */ uint16 xor_word(uint16 d, uint16 s) { register uint16 res; res = d ^ s; /* clear flags */ CLR_FLAG(OF); CLR_FLAG(CF); /* set the flags based on the result */ CONDITIONAL_SET_FLAG(res & 0x8000, SF); CONDITIONAL_SET_FLAG(res == 0, ZF); CONDITIONAL_SET_FLAG(parity(res & 0xFF), PF); return res; } /* memory routines. These use the segment register (segreg) value and offset (addr) to calculate the proper source or destination memory address */ /* get a byte from memory */ int32 get_smbyte(int32 segreg, int32 addr) { int32 abs_addr, val; abs_addr = addr + (get_rword(segreg) << 4); val = get_mbyte(abs_addr); // sim_printf("get_smbyte: seg=%04X addr=%04X abs_addr=%08X get_mbyte=%02X\n", // get_rword(segreg), addr, abs_addr, val); return val; } /* get a word from memory using addr and segment register */ int32 get_smword(int32 segreg, int32 addr) { int32 val; val = get_smbyte(segreg, addr); val |= (get_smbyte(segreg, addr+1) << 8); return val; } /* put a byte to memory using addr and segment register */ void put_smbyte(int32 segreg, int32 addr, int32 val) { int32 abs_addr; abs_addr = addr + (get_rword(segreg) << 4); put_mbyte(abs_addr, val); } /* put a word to memory using addr and segment register */ void put_smword(int32 segreg, int32 addr, int32 val) { put_smbyte(segreg, addr, val); put_smbyte(segreg, addr+1, val << 8); } /* Reset routine using addr and segment register */ t_stat i8088_reset (DEVICE *dptr) { PSW = 0; CS = 0xFFFF; DS = 0; SS = 0; ES = 0; saved_PC = 0; int_req = 0; sim_brk_types = sim_brk_dflt = SWMASK ('E'); sim_printf(" 8088 Reset\n"); return SCPE_OK; } /* Memory examine */ t_stat i8088_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { if (addr >= MAXMEMSIZE20) return SCPE_NXM; if (vptr != NULL) *vptr = get_mbyte(addr); return SCPE_OK; } /* Memory deposit */ t_stat i8088_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) { if (addr >= MAXMEMSIZE20) return SCPE_NXM; put_mbyte(addr, val); return SCPE_OK; } /* This is the binary loader. The input file is considered to be a string of literal bytes with no special format. The load starts at the current value of the PC. */ int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { int32 i, addr = 0, cnt = 0; if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; addr = saved_PC; while ((i = getc (fileref)) != EOF) { put_mbyte(addr, i); addr++; cnt++; } /* end while */ sim_printf ("%d Bytes loaded.\n", cnt); return (SCPE_OK); } /* Symbolic output Inputs: *of = output stream addr = current PC *val = pointer to values *uptr = pointer to unit sw = switches Outputs: status = error code */ int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) { int32 cflag, c1, c2, inst, adr; cflag = (uptr == NULL) || (uptr == &i8088_unit); c1 = (val[0] >> 8) & 0177; c2 = val[0] & 0177; if (sw & SWMASK ('A')) { fprintf (of, (c2 < 040)? "<%02X>": "%c", c2); return SCPE_OK; } if (sw & SWMASK ('C')) { fprintf (of, (c1 < 040)? "<%02X>": "%c", c1); fprintf (of, (c2 < 040)? "<%02X>": "%c", c2); return SCPE_OK; } if (!(sw & SWMASK ('M'))) return SCPE_ARG; inst = val[0]; fprintf (of, "%s", opcode[inst]); if (oplen[inst] == 2) { if (strchr(opcode[inst], ' ') != NULL) fprintf (of, ","); else fprintf (of, " "); fprintf (of, "%h", val[1]); } if (oplen[inst] == 3) { adr = val[1] & 0xFF; adr |= (val[2] << 8) & 0xff00; if (strchr(opcode[inst], ' ') != NULL) fprintf (of, ","); else fprintf (of, " "); fprintf (of, "%h", adr); } return -(oplen[inst] - 1); } /* Symbolic input Inputs: *cptr = pointer to input string addr = current PC *uptr = pointer to unit *val = pointer to output values sw = switches Outputs: status = error status */ int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) { int32 cflag, i = 0, j, r; char gbuf[CBUFSIZE]; cflag = (uptr == NULL) || (uptr == &i8088_unit); while (isspace (*cptr)) cptr++; /* absorb spaces */ if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ val[0] = (uint32) cptr[0]; return SCPE_OK; } if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ val[0] = ((uint32) cptr[0] << 8) + (uint32) cptr[1]; return SCPE_OK; } /* An instruction: get opcode (all characters until null, comma, or numeric (including spaces). */ while (1) { if (*cptr == ',' || *cptr == '\0' || isdigit(*cptr)) break; gbuf[i] = toupper(*cptr); cptr++; i++; } /* Allow for RST which has numeric as part of opcode */ if (toupper(gbuf[0]) == 'R' && toupper(gbuf[1]) == 'S' && toupper(gbuf[2]) == 'T') { gbuf[i] = toupper(*cptr); cptr++; i++; } /* Allow for 'MOV' which is only opcode that has comma in it. */ if (toupper(gbuf[0]) == 'M' && toupper(gbuf[1]) == 'O' && toupper(gbuf[2]) == 'V') { gbuf[i] = toupper(*cptr); cptr++; i++; gbuf[i] = toupper(*cptr); cptr++; i++; } /* kill trailing spaces if any */ gbuf[i] = '\0'; for (j = i - 1; gbuf[j] == ' '; j--) { gbuf[j] = '\0'; } /* find opcode in table */ for (j = 0; j < 256; j++) { if (strcmp(gbuf, opcode[j]) == 0) break; } if (j > 255) /* not found */ return SCPE_ARG; val[0] = j; /* store opcode */ if (oplen[j] < 2) /* if 1-byter we are done */ return SCPE_OK; if (*cptr == ',') cptr++; cptr = get_glyph(cptr, gbuf, 0); /* get address */ sscanf(gbuf, "%o", &r); if (oplen[j] == 2) { val[1] = r & 0xFF; return (-1); } val[1] = r & 0xFF; val[2] = (r >> 8) & 0xFF; return (-2); }