| /* 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 <stdio.h> |
| #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 = { |
| "CPU", //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; |
| } |
| sim_interval--; /* countdown clock */ |
| |
| 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; |
| } |
| |
| |
| 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); |
| } |