/***************************************************************************** * pce * *****************************************************************************/ /***************************************************************************** * File name: src/cpu/e8086/opcodes.c * * Created: 1996-04-28 by Hampa Hug * * Copyright: (C) 1996-2021 Hampa Hug * *****************************************************************************/ /***************************************************************************** * This program is free software. You can redistribute it and / or modify it * * under the terms of the GNU General Public License version 2 as published * * by the Free Software Foundation. * * * * This program 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. * *****************************************************************************/ #include "e8086.h" #include "internal.h" void e86_push (e8086_t *c, unsigned short val) { e86_set_sp (c, e86_get_sp (c) - 2); e86_set_mem16 (c, e86_get_ss (c), e86_get_sp (c), val); } unsigned short e86_pop (e8086_t *c) { unsigned short sp; sp = e86_get_sp (c); e86_set_sp (c, sp + 2); return (e86_get_mem16 (c, e86_get_ss (c), sp)); } /************************************************************************** * Microcode functions **************************************************************************/ /* Handle an undefined opcode */ static unsigned op_ud (e8086_t *c) { e86_set_clk (c, 1); return (e86_undefined (c)); } static unsigned op_divide_error (e8086_t *c) { e86_set_clk_ea (c, 16, 20); e86_set_ip (c, e86_get_ip (c) + c->ea.cnt + 1); e86_trap (c, 0); return (0); } /* OP 00: ADD r/m8, reg8 */ static unsigned op_00 (e8086_t *c) { unsigned short s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = e86_get_reg8 (c, (c->pq[1] >> 3) & 7); d = s1 + s2; e86_set_ea8 (c, d); e86_set_flg_add_8 (c, s1, s2); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP 01: ADD r/m16, reg16 */ static unsigned op_01 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_get_reg16 (c, (c->pq[1] >> 3) & 7); d = s1 + s2; e86_set_ea16 (c, d); e86_set_flg_add_16 (c, s1, s2); e86_set_clk_ea (clk, 3, 16); return (c->ea.cnt + 1); } /* OP 02: ADD reg8, r/m8 */ static unsigned op_02 (e8086_t *c) { unsigned reg; unsigned short s1, s2, d; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg8 (c, reg); s2 = e86_get_ea8 (c); d = s1 + s2; e86_set_reg8 (c, reg, d); e86_set_flg_add_8 (c, s1, s2); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 03: ADD reg16, r/m16 */ static unsigned op_03 (e8086_t *c) { unsigned reg; unsigned long s1, s2, d; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg16 (c, reg); s2 = e86_get_ea16 (c); d = s1 + s2; e86_set_reg16 (c, reg, d); e86_set_flg_add_16 (c, s1, s2); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 04: ADD AL, data8 */ static unsigned op_04 (e8086_t *c) { unsigned short s1, s2, d; s1 = e86_get_al (c); s2 = c->pq[1]; d = s1 + s2; e86_set_al (c, d); e86_set_flg_add_8 (c, s1, s2); e86_set_clk (c, 4); return (2); } /* OP 05: ADD AX, data16 */ static unsigned op_05 (e8086_t *c) { unsigned long s1, s2, d; s1 = e86_get_ax (c); s2 = e86_mk_uint16 (c->pq[1], c->pq[2]); d = s1 + s2; e86_set_ax (c, d); e86_set_flg_add_16 (c, s1, s2); e86_set_clk (c, 4); return (3); } /* OP 06: PUSH ES */ static unsigned op_06 (e8086_t *c) { e86_push (c, e86_get_es (c)); e86_set_clk (c, 10); return (1); } /* OP 07: POP ES */ static unsigned op_07 (e8086_t *c) { e86_set_es (c, e86_pop (c)); e86_set_clk (c, 8); return (1); } /* OP 08: OR r/m8, reg8 */ static unsigned op_08 (e8086_t *c) { unsigned short s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = e86_get_reg8 (c, (c->pq[1] >> 3) & 7); d = s1 | s2; e86_set_ea8 (c, d); e86_set_flg_log_8 (c, d); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP 09: OR r/m16, reg16 */ static unsigned op_09 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_get_reg16 (c, (c->pq[1] >> 3) & 7); d = s1 | s2; e86_set_ea16 (c, d); e86_set_flg_log_16 (c, d); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP 0A: OR reg8, r/m8 */ static unsigned op_0a (e8086_t *c) { unsigned reg; unsigned short s1, s2, d; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg8 (c, reg); s2 = e86_get_ea8 (c); d = s1 | s2; e86_set_reg8 (c, reg, d); e86_set_flg_log_8 (c, d); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 0B: OR reg16, r/m16 */ static unsigned op_0b (e8086_t *c) { unsigned reg; unsigned long s1, s2, d; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg16 (c, reg); s2 = e86_get_ea16 (c); d = s1 | s2; e86_set_reg16 (c, reg, d); e86_set_flg_log_16 (c, d); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 0C: OR AL, data8 */ static unsigned op_0c (e8086_t *c) { unsigned short s1, s2, d; s1 = e86_get_al (c); s2 = c->pq[1]; d = s1 | s2; e86_set_al (c, d); e86_set_flg_log_8 (c, d); e86_set_clk (c, 4); return (2); } /* OP 0D: OR AX, data16 */ static unsigned op_0d (e8086_t *c) { unsigned long s1, s2, d; s1 = e86_get_ax (c); s2 = e86_mk_uint16 (c->pq[1], c->pq[2]); d = s1 | s2; e86_set_ax (c, d); e86_set_flg_log_16 (c, d); e86_set_clk (c, 4); return (3); } /* OP 0E: PUSH CS */ static unsigned op_0e (e8086_t *c) { e86_push (c, e86_get_cs (c)); e86_set_clk (c, 10); return (1); } /* OP 0F: POP CS */ static unsigned op_0f (e8086_t *c) { e86_set_cs (c, e86_pop (c)); e86_pq_init (c); return (1); } /* OP 10: ADC r/m8, reg8 */ static unsigned op_10 (e8086_t *c) { unsigned short s1, s2, s3, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = e86_get_reg8 (c, (c->pq[1] >> 3) & 7); s3 = e86_get_cf (c); d = s1 + s2 + s3; e86_set_ea8 (c, d); e86_set_flg_adc_8 (c, s1, s2, s3); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP 11: ADC r/m16, reg16 */ static unsigned op_11 (e8086_t *c) { unsigned long s1, s2, s3, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_get_reg16 (c, (c->pq[1] >> 3) & 7); s3 = e86_get_cf (c); d = s1 + s2 + s3; e86_set_ea16 (c, d); e86_set_flg_adc_16 (c, s1, s2, s3); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP 12: ADC reg8, r/m8 */ static unsigned op_12 (e8086_t *c) { unsigned reg; unsigned short s1, s2, s3, d; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg8 (c, reg); s2 = e86_get_ea8 (c); s3 = e86_get_cf (c); d = s1 + s2 + s3; e86_set_reg8 (c, reg, d); e86_set_flg_adc_8 (c, s1, s2, s3); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 13: ADC reg16, r/m16 */ static unsigned op_13 (e8086_t *c) { unsigned reg; unsigned long s1, s2, s3, d; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg16 (c, reg); s2 = e86_get_ea16 (c); s3 = e86_get_cf (c); d = s1 + s2 + s3; e86_set_reg16 (c, reg, d); e86_set_flg_adc_16 (c, s1, s2, s3); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 14: ADC AL, data8 */ static unsigned op_14 (e8086_t *c) { unsigned short s1, s2, s3, d; s1 = e86_get_al (c); s2 = c->pq[1]; s3 = e86_get_cf (c); d = s1 + s2 + s3; e86_set_al (c, d); e86_set_flg_adc_8 (c, s1, s2, s3); e86_set_clk (c, 4); return (2); } /* OP 15: ADC AX, data16 */ static unsigned op_15 (e8086_t *c) { unsigned long s1, s2, s3, d; s1 = e86_get_ax (c); s2 = e86_mk_uint16 (c->pq[1], c->pq[2]); s3 = e86_get_cf (c); d = s1 + s2 + s3; e86_set_ax (c, d); e86_set_flg_adc_16 (c, s1, s2, s3); e86_set_clk (c, 4); return (3); } /* OP 16: PUSH SS */ static unsigned op_16 (e8086_t *c) { e86_push (c, e86_get_ss (c)); e86_set_clk (c, 10); return (1); } /* OP 17: POP SS */ static unsigned op_17 (e8086_t *c) { e86_set_ss (c, e86_pop (c)); e86_set_clk (c, 8); c->save_flags &= ~E86_FLG_I; return (1); } /* OP 18: SBB r/m8, reg8 */ static unsigned op_18 (e8086_t *c) { unsigned short s1, s2, s3, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = e86_get_reg8 (c, (c->pq[1] >> 3) & 7); s3 = e86_get_cf (c); d = s1 - s2 - s3; e86_set_ea8 (c, d); e86_set_flg_sbb_8 (c, s1, s2, s3); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP 19: SBB r/m16, reg16 "" */ static unsigned op_19 (e8086_t *c) { unsigned long s1, s2, s3, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_get_reg16 (c, (c->pq[1] >> 3) & 7); s3 = e86_get_cf (c); d = s1 - s2 - s3; e86_set_ea16 (c, d); e86_set_flg_sbb_16 (c, s1, s2, s3); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP 1A: SBB reg8, r/m8 */ static unsigned op_1a (e8086_t *c) { unsigned reg; unsigned short s1, s2, s3, d; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg8 (c, reg); s2 = e86_get_ea8 (c); s3 = e86_get_cf (c); d = s1 - s2 - s3; e86_set_reg8 (c, reg, d); e86_set_flg_sbb_8 (c, s1, s2, s3); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 1B: SBB reg16, r/m16 */ static unsigned op_1b (e8086_t *c) { unsigned reg; unsigned long s1, s2, s3, d; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg16 (c, reg); s2 = e86_get_ea16 (c); s3 = e86_get_cf (c); d = s1 - s2 - s3; e86_set_reg16 (c, reg, d); e86_set_flg_sbb_16 (c, s1, s2, s3); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 1C: SBB AL, data8 */ static unsigned op_1c (e8086_t *c) { unsigned short s1, s2, s3, d; s1 = e86_get_al (c); s2 = c->pq[1]; s3 = e86_get_cf (c); d = s1 - s2 - s3; e86_set_al (c, d); e86_set_flg_sbb_8 (c, s1, s2, s3); e86_set_clk (c, 4); return (2); } /* OP 1D: SBB AX, data16 */ static unsigned op_1d (e8086_t *c) { unsigned long s1, s2, s3, d; s1 = e86_get_ax (c); s2 = e86_mk_uint16 (c->pq[1], c->pq[2]); s3 = e86_get_cf (c); d = s1 - s2 - s3; e86_set_ax (c, d); e86_set_flg_sbb_16 (c, s1, s2, s3); e86_set_clk (c, 4); return (3); } /* OP 1E: PUSH DS */ static unsigned op_1e (e8086_t *c) { e86_push (c, e86_get_ds (c)); e86_set_clk (c, 10); return (1); } /* OP 1F: POP DS */ static unsigned op_1f (e8086_t *c) { e86_set_ds (c, e86_pop (c)); e86_set_clk (c, 8); return (1); } /* OP 20: AND r/m8, reg8 */ static unsigned op_20 (e8086_t *c) { unsigned short s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = e86_get_reg8 (c, (c->pq[1] >> 3) & 7); d = s1 & s2; e86_set_ea8 (c, d); e86_set_flg_log_8 (c, d); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP 21: AND r/m16, reg16 */ static unsigned op_21 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_get_reg16 (c, (c->pq[1] >> 3) & 7); d = s1 & s2; e86_set_ea16 (c, d); e86_set_flg_log_16 (c, d); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP 22: AND reg8, r/m8 */ static unsigned op_22 (e8086_t *c) { unsigned reg; unsigned short s1, s2, d; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg8 (c, reg); s2 = e86_get_ea8 (c); d = s1 & s2; e86_set_reg8 (c, reg, d); e86_set_flg_log_8 (c, d); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 23: AND reg16, r/m16 */ static unsigned op_23 (e8086_t *c) { unsigned reg; unsigned long s1, s2, d; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg16 (c, reg); s2 = e86_get_ea16 (c); d = s1 & s2; e86_set_reg16 (c, reg, d); e86_set_flg_log_16 (c, d); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 24: AND AL, data8 */ static unsigned op_24 (e8086_t *c) { unsigned short s1, s2, d; s1 = e86_get_al (c); s2 = c->pq[1]; d = s1 & s2; e86_set_al (c, d); e86_set_flg_log_8 (c, d); e86_set_clk (c, 4); return (2); } /* OP 25: AND AX, data16 */ static unsigned op_25 (e8086_t *c) { unsigned long s1, s2, d; s1 = e86_get_ax (c); s2 = e86_mk_uint16 (c->pq[1], c->pq[2]); d = s1 & s2; e86_set_ax (c, d); e86_set_flg_log_16 (c, d); e86_set_clk (c, 4); return (3); } /* OP 26: ES: */ static unsigned op_26 (e8086_t *c) { c->prefix |= (E86_PREFIX_NEW | E86_PREFIX_SEG); c->seg_override = c->sreg[E86_REG_ES]; return (1); } /* OP 27: DAA */ static unsigned op_27 (e8086_t *c) { unsigned al, cf; al = e86_get_al (c); cf = e86_get_cf (c); if (((al & 0x0f) > 9) || e86_get_af (c)) { al += 6; cf |= ((al & 0xff00) != 0); e86_set_af (c, 1); } else { e86_set_af (c, 0); } if (((al & 0xf0) > 0x90) || cf) { al += 0x60; e86_set_cf (c, 1); } else { e86_set_cf (c, 0); } e86_set_al (c, al); e86_set_flg_szp_8 (c, al); e86_set_clk (c, 4); return (1); } /* OP 28: SUB r/m8, reg8 */ static unsigned op_28 (e8086_t *c) { unsigned short s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = e86_get_reg8 (c, (c->pq[1] >> 3) & 7); d = s1 - s2; e86_set_ea8 (c, d); e86_set_flg_sub_8 (c, s1, s2); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP 29: SUB r/m16, reg16 */ static unsigned op_29 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_get_reg16 (c, (c->pq[1] >> 3) & 7); d = s1 - s2; e86_set_ea16 (c, d); e86_set_flg_sub_16 (c, s1, s2); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP 2A: SUB reg8, r/m8 */ static unsigned op_2a (e8086_t *c) { unsigned reg; unsigned short s1, s2, d; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg8 (c, reg); s2 = e86_get_ea8 (c); d = s1 - s2; e86_set_reg8 (c, reg, d); e86_set_flg_sub_8 (c, s1, s2); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 2B: SUB reg16, r/m16 */ static unsigned op_2b (e8086_t *c) { unsigned reg; unsigned long s1, s2, d; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg16 (c, reg); s2 = e86_get_ea16 (c); d = s1 - s2; e86_set_reg16 (c, reg, d); e86_set_flg_sub_16 (c, s1, s2); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 2C: SUB AL, data8 */ static unsigned op_2c (e8086_t *c) { unsigned short s1, s2, d; s1 = e86_get_al (c); s2 = c->pq[1]; d = s1 - s2; e86_set_al (c, d); e86_set_flg_sub_8 (c, s1, s2); e86_set_clk (c, 4); return (2); } /* OP 2D: SUB AX, data16 */ static unsigned op_2d (e8086_t *c) { unsigned long s1, s2, d; s1 = e86_get_ax (c); s2 = e86_mk_uint16 (c->pq[1], c->pq[2]); d = s1 - s2; e86_set_ax (c, d); e86_set_flg_sub_16 (c, s1, s2); e86_set_clk (c, 4); return (3); } /* OP 2E: CS: */ static unsigned op_2e (e8086_t *c) { c->prefix |= (E86_PREFIX_NEW | E86_PREFIX_SEG); c->seg_override = c->sreg[E86_REG_CS]; return (1); } /* OP 2F: DAS */ static unsigned op_2f (e8086_t *c) { unsigned al, cf; al = e86_get_al (c); cf = e86_get_cf (c); if (((al & 0x0f) > 9) || e86_get_af (c)) { al -= 6; cf |= ((al & 0xff00) != 0); e86_set_af (c, 1); } else { e86_set_af (c, 0); } if (((al & 0xf0) > 0x90) || cf) { al -= 0x60; e86_set_cf (c, 1); } else { e86_set_cf (c, 0); } e86_set_al (c, al); e86_set_flg_szp_8 (c, al); e86_set_clk (c, 4); return (1); } /* OP 30: XOR r/m8, reg8 */ static unsigned op_30 (e8086_t *c) { unsigned short s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = e86_get_reg8 (c, (c->pq[1] >> 3) & 7); d = s1 ^ s2; e86_set_ea8 (c, d); e86_set_flg_log_8 (c, d); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP 31: XOR r/m16, reg16 */ static unsigned op_31 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_get_reg16 (c, (c->pq[1] >> 3) & 7); d = s1 ^ s2; e86_set_ea16 (c, d); e86_set_flg_log_16 (c, d); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP 32: XOR reg8, r/m8 */ static unsigned op_32 (e8086_t *c) { unsigned reg; unsigned short s1, s2, d; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg8 (c, reg); s2 = e86_get_ea8 (c); d = s1 ^ s2; e86_set_reg8 (c, reg, d); e86_set_flg_log_8 (c, d); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 33: XOR reg16, r/m16 */ static unsigned op_33 (e8086_t *c) { unsigned reg; unsigned long s1, s2, d; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg16 (c, reg); s2 = e86_get_ea16 (c); d = s1 ^ s2; e86_set_reg16 (c, reg, d); e86_set_flg_log_16 (c, d); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 34: XOR AL, data8 */ static unsigned op_34 (e8086_t *c) { unsigned short s1, s2, d; s1 = e86_get_al (c); s2 = c->pq[1]; d = s1 ^ s2; e86_set_al (c, d); e86_set_flg_log_8 (c, d); e86_set_clk (c, 4); return (2); } /* OP 35: XOR AX, data16 */ static unsigned op_35 (e8086_t *c) { unsigned long s1, s2, d; s1 = e86_get_ax (c); s2 = e86_mk_uint16 (c->pq[1], c->pq[2]); d = s1 ^ s2; e86_set_ax (c, d); e86_set_flg_log_16 (c, d); e86_set_clk (c, 4); return (3); } /* OP 36: SS: */ static unsigned op_36 (e8086_t *c) { c->prefix |= (E86_PREFIX_NEW | E86_PREFIX_SEG); c->seg_override = c->sreg[E86_REG_SS]; return (1); } /* OP 37: AAA */ static unsigned op_37 (e8086_t *c) { unsigned ah, al; al = e86_get_al (c); ah = e86_get_ah (c); if (((al & 0x0f) > 9) || e86_get_af (c)) { al += 6; ah += 1; c->flg |= (E86_FLG_A | E86_FLG_C); } else { c->flg &= ~(E86_FLG_A | E86_FLG_C); } e86_set_ax (c, ((ah & 0xff) << 8) | (al & 0x0f)); e86_set_clk (c, 8); return (1); } /* OP 38: CMP r/m8, reg8 */ static unsigned op_38 (e8086_t *c) { unsigned short s1, s2; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = e86_get_reg8 (c, (c->pq[1] >> 3) & 7); e86_set_flg_sub_8 (c, s1, s2); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 39: CMP r/m16, reg16 */ static unsigned op_39 (e8086_t *c) { unsigned long s1, s2; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_get_reg16 (c, (c->pq[1] >> 3) & 7); e86_set_flg_sub_16 (c, s1, s2); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 3A: CMP reg8, r/m8 */ static unsigned op_3a (e8086_t *c) { unsigned short s1, s2; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg8 (c, (c->pq[1] >> 3) & 7); s2 = e86_get_ea8 (c); e86_set_flg_sub_8 (c, s1, s2); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 3B: CMP reg16, r/m16 */ static unsigned op_3b (e8086_t *c) { unsigned long s1, s2; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_reg16 (c, (c->pq[1] >> 3) & 7); s2 = e86_get_ea16 (c); e86_set_flg_sub_16 (c, s1, s2); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 3C: CMP AL, data8 */ static unsigned op_3c (e8086_t *c) { unsigned short s1, s2; s1 = e86_get_al (c); s2 = c->pq[1]; e86_set_flg_sub_8 (c, s1, s2); e86_set_clk (c, 4); return (2); } /* OP 3D: CMP AX, data16 */ static unsigned op_3d (e8086_t *c) { unsigned long s1, s2; s1 = e86_get_ax (c); s2 = e86_mk_uint16 (c->pq[1], c->pq[2]); e86_set_flg_sub_16 (c, s1, s2); e86_set_clk (c, 4); return (3); } /* OP 3E: DS: */ static unsigned op_3e (e8086_t *c) { c->prefix |= (E86_PREFIX_NEW | E86_PREFIX_SEG); c->seg_override = c->sreg[E86_REG_DS]; return (1); } /* OP 3F: AAS */ static unsigned op_3f (e8086_t *c) { unsigned ah, al; al = e86_get_al (c); ah = e86_get_ah (c); if (((al & 0x0f) > 9) || e86_get_af (c)) { al -= 6; ah -= 1; c->flg |= (E86_FLG_A | E86_FLG_C); } else { c->flg &= ~(E86_FLG_A | E86_FLG_C); } e86_set_ax (c, ((ah & 0xff) << 8) | (al & 0x0f)); e86_set_clk (c, 8); return (1); } /* OP 4x: INC reg16 */ static unsigned op_40 (e8086_t *c) { unsigned r; unsigned short cf; unsigned long s; r = c->pq[0] & 7; s = c->dreg[r]; c->dreg[r] = (s + 1) & 0xffff; cf = c->flg; e86_set_flg_add_16 (c, s, 1); c->flg ^= (c->flg ^ cf) & E86_FLG_C; e86_set_clk (c, 3); return (1); } /* OP 4x: DEC reg16 */ static unsigned op_48 (e8086_t *c) { unsigned r; unsigned short cf; unsigned long s; r = c->pq[0] & 7; s = c->dreg[r]; c->dreg[r] = (s - 1) & 0xffff; cf = c->flg; e86_set_flg_sub_16 (c, s, 1); c->flg ^= (c->flg ^ cf) & E86_FLG_C; e86_set_clk (c, 3); return (1); } /* OP 5x: PUSH reg16 */ static unsigned op_50 (e8086_t *c) { unsigned reg; reg = c->pq[0] & 7; if ((reg == E86_REG_SP) && ((c->cpu & E86_CPU_PUSH_FIRST) == 0)) { e86_push (c, e86_get_sp (c) - 2); } else { e86_push (c, e86_get_reg16 (c, reg)); } e86_set_clk (c, 10); return (1); } /* OP 5x: POP reg16 */ static unsigned op_58 (e8086_t *c) { unsigned short val; val = e86_pop (c); e86_set_reg16 (c, c->pq[0] & 7, val); e86_set_clk (c, 8); return (1); } /* OP 66: hook */ static unsigned op_66 (e8086_t *c) { unsigned short cs, ip; if (c->pq[1] != 0x66) { return (op_ud (c)); } cs = e86_get_cs (c); ip = e86_get_ip (c); if (c->op_hook != NULL) { c->op_hook (c->op_ext, c->pq[2], c->pq[3]); } e86_set_clk (c, 16); if ((e86_get_cs (c) != cs) || (e86_get_ip (c) != ip)) { return (0); } return (4); } /* OP 70: JO imm8 */ static unsigned op_70 (e8086_t *c) { if (e86_get_of (c)) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 71: JNO imm8 */ static unsigned op_71 (e8086_t *c) { if (!e86_get_of (c)) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 72: JB imm8 */ static unsigned op_72 (e8086_t *c) { if (e86_get_cf (c)) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 73: JAE imm8 */ static unsigned op_73 (e8086_t *c) { if (!e86_get_cf (c)) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 74: JE imm8 */ static unsigned op_74 (e8086_t *c) { if (e86_get_zf (c)) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 75: JNE imm8 */ static unsigned op_75 (e8086_t *c) { if (!e86_get_zf (c)) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 76: JBE imm8 */ static unsigned op_76 (e8086_t *c) { if (e86_get_zf (c) || e86_get_cf (c)) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 77: JA imm8 */ static unsigned op_77 (e8086_t *c) { if (!(e86_get_zf (c) || e86_get_cf (c))) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 78: JS imm8 */ static unsigned op_78 (e8086_t *c) { if (e86_get_sf (c)) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 79: JNS imm8 */ static unsigned op_79 (e8086_t *c) { if (!e86_get_sf (c)) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 7A: JPE imm8 */ static unsigned op_7a (e8086_t *c) { if (e86_get_pf (c)) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 7B: JPO imm8 */ static unsigned op_7b (e8086_t *c) { if (!e86_get_pf (c)) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 7C: JL imm8 */ static unsigned op_7c (e8086_t *c) { if (e86_get_sf (c) != e86_get_of (c)) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 7D: JGE imm8 */ static unsigned op_7d (e8086_t *c) { if (e86_get_sf (c) == e86_get_of (c)) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 7E: JLE imm8 */ static unsigned op_7e (e8086_t *c) { if ((e86_get_sf (c) != e86_get_of (c)) || e86_get_zf (c)) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 7F: JG imm8 */ static unsigned op_7f (e8086_t *c) { if ((e86_get_sf (c) == e86_get_of (c)) && (!e86_get_zf (c))) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 16); return (0); } e86_set_clk (c, 4); return (2); } /* OP 80 00: ADD r/m8, imm8 */ static unsigned op_80_00 (e8086_t *c) { unsigned short s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = c->pq[c->ea.cnt + 1]; d = s1 + s2; e86_set_ea8 (c, d & 0xff); e86_set_flg_add_8 (c, s1, s2); e86_set_clk_ea (c, 4, 17); return (2 + c->ea.cnt); } /* OP 80 01: OR r/m8, imm8 */ static unsigned op_80_01 (e8086_t *c) { unsigned short s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = c->pq[c->ea.cnt + 1]; d = s1 | s2; e86_set_ea8 (c, d & 0xff); e86_set_flg_log_8 (c, d); e86_set_clk_ea (c, 4, 17); return (2 + c->ea.cnt); } /* OP 80 02: ADC r/m8, imm8 */ static unsigned op_80_02 (e8086_t *c) { unsigned short s1, s2, s3, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = c->pq[c->ea.cnt + 1]; s3 = e86_get_cf (c); d = s1 + s2 + s3; e86_set_ea8 (c, d & 0xff); e86_set_flg_adc_8 (c, s1, s2, s3); e86_set_clk_ea (c, 4, 17); return (2 + c->ea.cnt); } /* OP 80 03: SBB r/m8, imm8 */ static unsigned op_80_03 (e8086_t *c) { unsigned short s1, s2, s3, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = c->pq[c->ea.cnt + 1]; s3 = e86_get_cf (c); d = s1 - s2 - s3; e86_set_ea8 (c, d & 0xff); e86_set_flg_sbb_8 (c, s1, s2, s3); e86_set_clk_ea (c, 4, 17); return (2 + c->ea.cnt); } /* OP 80 04: AND r/m8, imm8 */ static unsigned op_80_04 (e8086_t *c) { unsigned short s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = c->pq[c->ea.cnt + 1]; d = s1 & s2; e86_set_ea8 (c, d); e86_set_flg_log_8 (c, d); e86_set_clk_ea (c, 4, 17); return (2 + c->ea.cnt); } /* OP 80 05: SUB r/m8, imm8 */ static unsigned op_80_05 (e8086_t *c) { unsigned short s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = c->pq[c->ea.cnt + 1]; d = s1 - s2; e86_set_ea8 (c, d & 0xff); e86_set_flg_sub_8 (c, s1, s2); e86_set_clk_ea (c, 4, 17); return (2 + c->ea.cnt); } /* OP 80 06: XOR r/m8, imm8 */ static unsigned op_80_06 (e8086_t *c) { unsigned short s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = c->pq[c->ea.cnt + 1]; d = s1 ^ s2; e86_set_ea8 (c, d); e86_set_flg_log_8 (c, d); e86_set_clk_ea (c, 4, 17); return (2 + c->ea.cnt); } /* OP 80 07: CMP r/m8, imm8 */ static unsigned op_80_07 (e8086_t *c) { unsigned short s1, s2; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = c->pq[c->ea.cnt + 1]; e86_set_flg_sub_8 (c, s1, s2); e86_set_clk_ea (c, 4, 10); return (2 + c->ea.cnt); } static e86_opcode_f e86_opcodes_80[8] = { &op_80_00, &op_80_01, &op_80_02, &op_80_03, &op_80_04, &op_80_05, &op_80_06, &op_80_07, }; /* OP 80: xxx r/m8, imm8 */ static unsigned op_80 (e8086_t *c) { unsigned xop; xop = (c->pq[1] >> 3) & 7; return (e86_opcodes_80[xop] (c)); } /* OP 81 00: ADD r/m16, imm16 */ static unsigned op_81_00 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_uint16 (c->pq[c->ea.cnt + 1], c->pq[c->ea.cnt + 2]); d = s1 + s2; e86_set_ea16 (c, d & 0xffff); e86_set_flg_add_16 (c, s1, s2); e86_set_clk_ea (c, 4, 17); return (3 + c->ea.cnt); } /* OP 81 01: OR r/m16, imm16 */ static unsigned op_81_01 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_uint16 (c->pq[c->ea.cnt + 1], c->pq[c->ea.cnt + 2]); d = s1 | s2; e86_set_ea16 (c, d & 0xffff); e86_set_flg_log_16 (c, d); e86_set_clk_ea (c, 4, 17); return (3 + c->ea.cnt); } /* OP 81 02: ADC r/m16, imm16 */ static unsigned op_81_02 (e8086_t *c) { unsigned long s1, s2, s3, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_uint16 (c->pq[c->ea.cnt + 1], c->pq[c->ea.cnt + 2]); s3 = e86_get_cf (c); d = s1 + s2 + s3; e86_set_ea16 (c, d & 0xffff); e86_set_flg_adc_16 (c, s1, s2, s3); e86_set_clk_ea (c, 4, 17); return (3 + c->ea.cnt); } /* OP 81 03: SBB r/m16, imm16 */ static unsigned op_81_03 (e8086_t *c) { unsigned long s1, s2, s3, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_uint16 (c->pq[c->ea.cnt + 1], c->pq[c->ea.cnt + 2]); s3 = e86_get_cf (c); d = s1 - s2 - s3; e86_set_ea16 (c, d & 0xffff); e86_set_flg_sbb_16 (c, s1, s2, s3); e86_set_clk_ea (c, 4, 17); return (3 + c->ea.cnt); } /* OP 81 04: AND r/m16, imm16 */ static unsigned op_81_04 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_uint16 (c->pq[c->ea.cnt + 1], c->pq[c->ea.cnt + 2]); d = s1 & s2; e86_set_ea16 (c, d); e86_set_flg_log_16 (c, d); e86_set_clk_ea (c, 4, 17); return (3 + c->ea.cnt); } /* OP 81 05: SUB r/m16, imm16 */ static unsigned op_81_05 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_uint16 (c->pq[c->ea.cnt + 1], c->pq[c->ea.cnt + 2]); d = s1 - s2; e86_set_ea16 (c, d & 0xffff); e86_set_flg_sub_16 (c, s1, s2); e86_set_clk_ea (c, 4, 17); return (3 + c->ea.cnt); } /* OP 81 06: XOR r/m16, imm16 */ static unsigned op_81_06 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_uint16 (c->pq[c->ea.cnt + 1], c->pq[c->ea.cnt + 2]); d = s1 ^ s2; e86_set_ea16 (c, d); e86_set_flg_log_16 (c, d); e86_set_clk_ea (c, 4, 17); return (3 + c->ea.cnt); } /* OP 81 07: CMP r/m16, imm16 */ static unsigned op_81_07 (e8086_t *c) { unsigned long s1, s2; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_uint16 (c->pq[c->ea.cnt + 1], c->pq[c->ea.cnt + 2]); e86_set_flg_sub_16 (c, s1, s2); e86_set_clk_ea (c, 4, 10); return (3 + c->ea.cnt); } static e86_opcode_f e86_opcodes_81[8] = { &op_81_00, &op_81_01, &op_81_02, &op_81_03, &op_81_04, &op_81_05, &op_81_06, &op_81_07, }; /* OP 81: xxx r/m16, imm16 */ static unsigned op_81 (e8086_t *c) { unsigned xop; xop = (c->pq[1] >> 3) & 7; return (e86_opcodes_81[xop] (c)); } /* OP 83 00: ADD r/m16, imm8 */ static unsigned op_83_00 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_sint16 (c->pq[c->ea.cnt + 1]); d = s1 + s2; e86_set_ea16 (c, d); e86_set_flg_add_16 (c, s1, s2); e86_set_clk_ea (c, 4, 17); return (2 + c->ea.cnt); } /* OP 83 01: OR r/m16, imm8 */ static unsigned op_83_01 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_sint16 (c->pq[c->ea.cnt + 1]); d = s1 | s2; e86_set_ea16 (c, d); e86_set_flg_log_16 (c, d); e86_set_clk_ea (c, 4, 17); return (2 + c->ea.cnt); } /* OP 83 02: ADC r/m16, imm8 */ static unsigned op_83_02 (e8086_t *c) { unsigned long s1, s2, s3, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_sint16 (c->pq[c->ea.cnt + 1]); s3 = e86_get_cf (c); d = s1 + s2 + s3; e86_set_ea16 (c, d); e86_set_flg_adc_16 (c, s1, s2, s3); e86_set_clk_ea (c, 4, 17); return (2 + c->ea.cnt); } /* OP 83 03: SBB r/m16, imm8 */ static unsigned op_83_03 (e8086_t *c) { unsigned long s1, s2, s3, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_sint16 (c->pq[c->ea.cnt + 1]); s3 = e86_get_cf (c); d = s1 - s2 - s3; e86_set_ea16 (c, d); e86_set_flg_sbb_16 (c, s1, s2, s3); e86_set_clk_ea (c, 4, 17); return (2 + c->ea.cnt); } /* OP 83 04: AND r/m16, imm8 */ static unsigned op_83_04 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_sint16 (c->pq[c->ea.cnt + 1]); d = s1 & s2; e86_set_ea16 (c, d); e86_set_flg_log_16 (c, d); e86_set_clk_ea (c, 4, 17); return (2 + c->ea.cnt); } /* OP 83 05: SUB r/m16, imm8 */ static unsigned op_83_05 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_sint16 (c->pq[c->ea.cnt + 1]); d = s1 - s2; e86_set_ea16 (c, d); e86_set_flg_sub_16 (c, s1, s2); e86_set_clk_ea (c, 4, 17); return (2 + c->ea.cnt); } /* OP 83 06: XOR r/m16, imm8 */ static unsigned op_83_06 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_sint16 (c->pq[c->ea.cnt + 1]); d = s1 ^ s2; e86_set_ea16 (c, d); e86_set_flg_log_16 (c, d); e86_set_clk_ea (c, 4, 17); return (2 + c->ea.cnt); } /* OP 83 07: CMP r/m16, imm8 */ static unsigned op_83_07 (e8086_t *c) { unsigned long s1, s2; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_sint16 (c->pq[c->ea.cnt + 1]); e86_set_flg_sub_16 (c, s1, s2); e86_set_clk_ea (c, 4, 10); return (2 + c->ea.cnt); } static e86_opcode_f e86_opcodes_83[8] = { &op_83_00, &op_83_01, &op_83_02, &op_83_03, &op_83_04, &op_83_05, &op_83_06, &op_83_07, }; /* OP 83: xxx r/m16, imm8 */ static unsigned op_83 (e8086_t *c) { unsigned xop; xop = (c->pq[1] >> 3) & 7; return (e86_opcodes_83[xop] (c)); } /* OP 84: TEST r/m8, reg8 */ static unsigned op_84 (e8086_t *c) { unsigned short s1, s2; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = e86_get_reg8 (c, (c->pq[1] >> 3) & 7); e86_set_flg_log_8 (c, s1 & s2); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 85: TEST r/m16, reg16 */ static unsigned op_85 (e8086_t *c) { unsigned long s1, s2; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_get_reg16 (c, (c->pq[1] >> 3) & 7); e86_set_flg_log_16 (c, s1 & s2); e86_set_clk_ea (c, 3, 9); return (c->ea.cnt + 1); } /* OP 86: XCHG r/m8, reg8 */ static unsigned op_86 (e8086_t *c) { unsigned reg; unsigned short s1, s2; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = e86_get_reg8 (c, reg); e86_set_ea8 (c, s2); e86_set_reg8 (c, reg, s1); e86_set_clk_ea (c, 4, 17); return (c->ea.cnt + 1); } /* OP 87: XCHG r/m16, reg16 */ static unsigned op_87 (e8086_t *c) { unsigned reg; unsigned long s1, s2; reg = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_get_reg16 (c, reg); e86_set_ea16 (c, s2); e86_set_reg16 (c, reg, s1); e86_set_clk_ea (c, 4, 17); return (c->ea.cnt + 1); } /* OP 88: MOV r/m8, reg8 */ static unsigned op_88 (e8086_t *c) { unsigned char val; unsigned reg; e86_get_ea_ptr (c, c->pq + 1); reg = (c->pq[1] >> 3) & 7; val = e86_get_reg8 (c, reg); e86_set_ea8 (c, val); e86_set_clk_ea (c, 2, 9); return (c->ea.cnt + 1); } /* OP 89: MOV r/m16, reg16 */ static unsigned op_89 (e8086_t *c) { unsigned short val; unsigned reg; e86_get_ea_ptr (c, c->pq + 1); reg = (c->pq[1] >> 3) & 7; val = e86_get_reg16 (c, reg); e86_set_ea16 (c, val); e86_set_clk_ea (c, 2, 9); return (c->ea.cnt + 1); } /* OP 8A: MOV reg8, r/m8 */ static unsigned op_8a (e8086_t *c) { unsigned char val; unsigned reg; e86_get_ea_ptr (c, c->pq + 1); reg = (c->pq[1] >> 3) & 7; val = e86_get_ea8 (c); e86_set_reg8 (c, reg, val); e86_set_clk_ea (c, 2, 8); return (c->ea.cnt + 1); } /* OP 8B: MOV reg16, r/m16 */ static unsigned op_8b (e8086_t *c) { unsigned short val; unsigned reg; e86_get_ea_ptr (c, c->pq + 1); reg = (c->pq[1] >> 3) & 7; val = e86_get_ea16 (c); e86_set_reg16 (c, reg, val); e86_set_clk_ea (c, 2, 8); return (c->ea.cnt + 1); } /* OP 8C: MOV r/m16, sreg */ static unsigned op_8c (e8086_t *c) { e86_get_ea_ptr (c, c->pq + 1); e86_set_ea16 (c, c->sreg[(c->pq[1] >> 3) & 3]); e86_set_clk_ea (c, 2, 9); return (c->ea.cnt + 1); } /* OP 8D: LEA reg16, r/m16 */ static unsigned op_8d (e8086_t *c) { e86_get_ea_ptr (c, c->pq + 1); if (c->ea.is_mem) { e86_set_reg16 (c, (c->pq[1] >> 3) & 7, c->ea.ofs); e86_set_clk (c, 2); } else { if (e86_undefined (c) == 0) { return (0); } } return (c->ea.cnt + 1); } /* OP 8E: MOV sreg, r/m16 */ static unsigned op_8e (e8086_t *c) { unsigned reg; reg = (c->pq[1] >> 3) & 3; e86_get_ea_ptr (c, c->pq + 1); e86_set_sreg (c, reg, e86_get_ea16 (c)); e86_set_clk_ea (c, 2, 8); if (reg == E86_REG_CS) { e86_pq_init (c); } else if (reg == E86_REG_SS) { c->save_flags &= ~E86_FLG_I; } return (c->ea.cnt + 1); } /* OP 8F: POP r/m16 */ static unsigned op_8f (e8086_t *c) { e86_get_ea_ptr (c, c->pq + 1); e86_set_ea16 (c, e86_pop (c)); e86_set_clk_ea (c, 8, 17); return (c->ea.cnt + 1); } /* OP 9x: XCHG AX, reg16 */ static unsigned op_90 (e8086_t *c) { unsigned reg; unsigned short val; reg = c->pq[0] & 7; val = e86_get_ax (c); e86_set_ax (c, e86_get_reg16 (c, reg)); e86_set_reg16 (c, reg, val); e86_set_clk (c, 3); return (1); } /* OP 98: CBW */ static unsigned op_98 (e8086_t *c) { e86_set_ax (c, e86_mk_sint16 (e86_get_al (c))); e86_set_clk (c, 2); return (1); } /* OP 99: CWD */ static unsigned op_99 (e8086_t *c) { e86_set_dx (c, (e86_get_ax (c) & 0x8000) ? 0xffff : 0x0000); e86_set_clk (c, 5); return (1); } /* OP 9A: CALL seg:ofs */ static unsigned op_9a (e8086_t *c) { e86_push (c, e86_get_cs (c)); e86_push (c, e86_get_ip (c) + 5); e86_set_ip (c, e86_mk_uint16 (c->pq[1], c->pq[2])); e86_set_cs (c, e86_mk_uint16 (c->pq[3], c->pq[4])); e86_pq_init (c); e86_set_clk (c, 28); return (0); } /* OP 9B: WAIT */ static unsigned op_9b (e8086_t *c) { e86_set_clk (c, 4); return (1); } /* OP 9C: PUSHF */ static unsigned op_9c (e8086_t *c) { if (c->cpu & E86_CPU_FLAGS286) { e86_push (c, c->flg & 0x0fd5); } else { e86_push (c, (c->flg & 0x0fd5) | 0xf002); } e86_set_clk (c, 10); return (1); } /* OP 9D: POPF */ static unsigned op_9d (e8086_t *c) { c->flg = (e86_pop (c) & 0x0fd5) | 0xf002; e86_set_clk (c, 8); return (1); } /* OP 9E: SAHF */ static unsigned op_9e (e8086_t *c) { c->flg &= 0xff00; c->flg |= e86_get_ah (c) & 0xd5; c->flg |= 0x02; e86_set_clk (c, 4); return (1); } /* OP 9F: LAHF */ static unsigned op_9f (e8086_t *c) { e86_set_ah (c, (c->flg & 0xd5) | 0x02); e86_set_clk (c, 4); return (1); } /* OP A0: MOV AL, [data16] */ static unsigned op_a0 (e8086_t *c) { unsigned short seg, ofs; unsigned char val; seg = e86_get_seg (c, E86_REG_DS); ofs = e86_mk_uint16 (c->pq[1], c->pq[2]); val = e86_get_mem8 (c, seg, ofs); e86_set_al (c, val); e86_set_clk (c, 10); return (3); } /* OP A1: MOV AX, [data16] */ static unsigned op_a1 (e8086_t *c) { unsigned short seg, ofs; seg = e86_get_seg (c, E86_REG_DS); ofs = e86_mk_uint16 (c->pq[1], c->pq[2]); e86_set_ax (c, e86_get_mem16 (c, seg, ofs)); e86_set_clk (c, 10); return (3); } /* OP A2: MOV [data16], AL */ static unsigned op_a2 (e8086_t *c) { unsigned short seg, ofs; seg = e86_get_seg (c, E86_REG_DS); ofs = e86_mk_uint16 (c->pq[1], c->pq[2]); e86_set_mem8 (c, seg, ofs, c->dreg[E86_REG_AX] & 0xff); e86_set_clk (c, 10); return (3); } /* OP A3: MOV [data16], AX */ static unsigned op_a3 (e8086_t *c) { unsigned short seg, ofs; seg = e86_get_seg (c, E86_REG_DS); ofs = e86_mk_uint16 (c->pq[1], c->pq[2]); e86_set_mem16 (c, seg, ofs, c->dreg[E86_REG_AX]); e86_set_clk (c, 10); return (3); } /* OP A4: MOVSB */ static unsigned op_a4 (e8086_t *c) { unsigned char val; unsigned short seg1, seg2; unsigned short inc; seg1 = e86_get_seg (c, E86_REG_DS); seg2 = e86_get_es (c); inc = e86_get_df (c) ? 0xffff : 0x0001; if (c->prefix & (E86_PREFIX_REP | E86_PREFIX_REPN)) { if (e86_get_cx (c) != 0) { val = e86_get_mem8 (c, seg1, e86_get_si (c)); e86_set_mem8 (c, seg2, e86_get_di (c), val); e86_set_si (c, e86_get_si (c) + inc); e86_set_di (c, e86_get_di (c) + inc); e86_set_cx (c, e86_get_cx (c) - 1); } e86_set_clk (c, 18); if (e86_get_cx (c) == 0) { c->prefix &= ~E86_PREFIX_KEEP; return (1); } c->prefix |= E86_PREFIX_KEEP; return (0); } else { val = e86_get_mem8 (c, seg1, e86_get_si (c)); e86_set_mem8 (c, seg2, e86_get_di (c), val); e86_set_si (c, e86_get_si (c) + inc); e86_set_di (c, e86_get_di (c) + inc); e86_set_clk (c, 18); } return (1); } /* OP A5: MOVSW */ static unsigned op_a5 (e8086_t *c) { unsigned short val; unsigned short seg1, seg2; unsigned short inc; seg1 = e86_get_seg (c, E86_REG_DS); seg2 = e86_get_es (c); inc = e86_get_df (c) ? 0xfffe : 0x0002; if (c->prefix & (E86_PREFIX_REP | E86_PREFIX_REPN)) { if (e86_get_cx (c) != 0) { val = e86_get_mem16 (c, seg1, e86_get_si (c)); e86_set_mem16 (c, seg2, e86_get_di (c), val); e86_set_si (c, e86_get_si (c) + inc); e86_set_di (c, e86_get_di (c) + inc); e86_set_cx (c, e86_get_cx (c) - 1); } e86_set_clk (c, 18); if (e86_get_cx (c) == 0) { c->prefix &= ~E86_PREFIX_KEEP; return (1); } c->prefix |= E86_PREFIX_KEEP; return (0); } else { val = e86_get_mem16 (c, seg1, e86_get_si (c)); e86_set_mem16 (c, seg2, e86_get_di (c), val); e86_set_si (c, e86_get_si (c) + inc); e86_set_di (c, e86_get_di (c) + inc); e86_set_clk (c, 18); } return (1); } /* Opcode A6: CMPSB */ static unsigned op_a6 (e8086_t *c) { unsigned short s1, s2; unsigned short seg1, seg2; unsigned short inc; int z; seg1 = e86_get_seg (c, E86_REG_DS); seg2 = e86_get_es (c); inc = e86_get_df (c) ? 0xffff : 0x0001; if (c->prefix & (E86_PREFIX_REP | E86_PREFIX_REPN)) { if (e86_get_cx (c) != 0) { s1 = e86_get_mem8 (c, seg1, e86_get_si (c)); s2 = e86_get_mem8 (c, seg2, e86_get_di (c)); e86_set_si (c, e86_get_si (c) + inc); e86_set_di (c, e86_get_di (c) + inc); e86_set_cx (c, e86_get_cx (c) - 1); e86_set_flg_sub_8 (c, s1, s2); } e86_set_clk (c, 22); z = (c->prefix & E86_PREFIX_REP) ? 1 : 0; if ((e86_get_cx (c) == 0) || (e86_get_zf (c) != z)) { c->prefix &= ~E86_PREFIX_KEEP; return (1); } c->prefix |= E86_PREFIX_KEEP; return (0); } else { s1 = e86_get_mem8 (c, seg1, e86_get_si (c)); s2 = e86_get_mem8 (c, seg2, e86_get_di (c)); e86_set_si (c, e86_get_si (c) + inc); e86_set_di (c, e86_get_di (c) + inc); e86_set_flg_sub_8 (c, s1, s2); e86_set_clk (c, 22); } return (1); } /* Opcode A7: CMPSW */ static unsigned op_a7 (e8086_t *c) { unsigned long s1, s2; unsigned short seg1, seg2; unsigned short inc; int z; seg1 = e86_get_seg (c, E86_REG_DS); seg2 = e86_get_es (c); inc = e86_get_df (c) ? 0xfffe : 0x0002; if (c->prefix & (E86_PREFIX_REP | E86_PREFIX_REPN)) { if (e86_get_cx (c) != 0) { s1 = e86_get_mem16 (c, seg1, e86_get_si (c)); s2 = e86_get_mem16 (c, seg2, e86_get_di (c)); e86_set_si (c, e86_get_si (c) + inc); e86_set_di (c, e86_get_di (c) + inc); e86_set_cx (c, e86_get_cx (c) - 1); e86_set_flg_sub_16 (c, s1, s2); } e86_set_clk (c, 22); z = (c->prefix & E86_PREFIX_REP) ? 1 : 0; if ((e86_get_cx (c) == 0) || (e86_get_zf (c) != z)) { c->prefix &= ~E86_PREFIX_KEEP; return (1); } c->prefix |= E86_PREFIX_KEEP; return (0); } else { s1 = e86_get_mem16 (c, seg1, e86_get_si (c)); s2 = e86_get_mem16 (c, seg2, e86_get_di (c)); e86_set_si (c, e86_get_si (c) + inc); e86_set_di (c, e86_get_di (c) + inc); e86_set_flg_sub_16 (c, s1, s2); e86_set_clk (c, 22); } return (1); } /* Opcode A8: TEST AL, data8 */ static unsigned op_a8 (e8086_t *c) { unsigned short s1, s2; s1 = e86_get_al (c); s2 = c->pq[1]; e86_set_flg_log_8 (c, s1 & s2); e86_set_clk (c, 4); return (2); } /* Opcode A9: TEST AX, data16 */ static unsigned op_a9 (e8086_t *c) { unsigned long s1, s2; s1 = e86_get_ax (c); s2 = e86_mk_uint16 (c->pq[1], c->pq[2]); e86_set_flg_log_16 (c, s1 & s2); e86_set_clk (c, 4); return (3); } /* Opcode AA: STOSB */ static unsigned op_aa (e8086_t *c) { unsigned short seg; unsigned short inc; seg = e86_get_es (c); inc = e86_get_df (c) ? 0xffff : 0x0001; if (c->prefix & (E86_PREFIX_REP | E86_PREFIX_REPN)) { if (e86_get_cx (c) != 0) { e86_set_mem8 (c, seg, e86_get_di (c), e86_get_al (c)); e86_set_di (c, e86_get_di (c) + inc); e86_set_cx (c, e86_get_cx (c) - 1); } e86_set_clk (c, 11); if (e86_get_cx (c) == 0) { c->prefix &= ~E86_PREFIX_KEEP; return (1); } c->prefix |= E86_PREFIX_KEEP; return (0); } else { e86_set_mem8 (c, seg, e86_get_di (c), e86_get_al (c)); e86_set_di (c, e86_get_di (c) + inc); e86_set_clk (c, 11); } return (1); } /* Opcode AB: STOSW */ static unsigned op_ab (e8086_t *c) { unsigned short seg; unsigned short inc; seg = e86_get_es (c); inc = e86_get_df (c) ? 0xfffe : 0x0002; if (c->prefix & (E86_PREFIX_REP | E86_PREFIX_REPN)) { if (e86_get_cx (c) != 0) { e86_set_mem16 (c, seg, e86_get_di (c), e86_get_ax (c)); e86_set_di (c, e86_get_di (c) + inc); e86_set_cx (c, e86_get_cx (c) - 1); } e86_set_clk (c, 11); if (e86_get_cx (c) == 0) { c->prefix &= ~E86_PREFIX_KEEP; return (1); } c->prefix |= E86_PREFIX_KEEP; return (0); } else { e86_set_mem16 (c, seg, e86_get_di (c), e86_get_ax (c)); e86_set_di (c, e86_get_di (c) + inc); e86_set_clk (c, 11); } return (1); } /* Opcode AC: LODSB */ static unsigned op_ac (e8086_t *c) { unsigned short seg; unsigned short inc; seg = e86_get_seg (c, E86_REG_DS); inc = e86_get_df (c) ? 0xffff : 0x0001; if (c->prefix & (E86_PREFIX_REP | E86_PREFIX_REPN)) { if (e86_get_cx (c) != 0) { e86_set_al (c, e86_get_mem8 (c, seg, e86_get_si (c))); e86_set_si (c, e86_get_si (c) + inc); e86_set_cx (c, e86_get_cx (c) - 1); } e86_set_clk (c, 12); if (e86_get_cx (c) == 0) { c->prefix &= ~E86_PREFIX_KEEP; return (1); } c->prefix |= E86_PREFIX_KEEP; return (0); } else { e86_set_al (c, e86_get_mem8 (c, seg, e86_get_si (c))); e86_set_si (c, e86_get_si (c) + inc); e86_set_clk (c, 12); } return (1); } /* Opcode AD: LODSW */ static unsigned op_ad (e8086_t *c) { unsigned short seg; unsigned short inc; seg = e86_get_seg (c, E86_REG_DS); inc = e86_get_df (c) ? 0xfffe : 0x0002; if (c->prefix & (E86_PREFIX_REP | E86_PREFIX_REPN)) { if (e86_get_cx (c) != 0) { e86_set_ax (c, e86_get_mem16 (c, seg, e86_get_si (c))); e86_set_si (c, e86_get_si (c) + inc); e86_set_cx (c, e86_get_cx (c) - 1); } e86_set_clk (c, 12); if (e86_get_cx (c) == 0) { c->prefix &= ~E86_PREFIX_KEEP; return (1); } c->prefix |= E86_PREFIX_KEEP; return (0); } else { e86_set_ax (c, e86_get_mem16 (c, seg, e86_get_si (c))); e86_set_si (c, e86_get_si (c) + inc); e86_set_clk (c, 12); } return (1); } /* Opcode AE: SCASB */ static unsigned op_ae (e8086_t *c) { unsigned short s1, s2; unsigned short seg; unsigned short inc; int z; seg = e86_get_es (c); inc = e86_get_df (c) ? 0xffff : 0x0001; if (c->prefix & (E86_PREFIX_REP | E86_PREFIX_REPN)) { if (e86_get_cx (c) != 0) { s1 = e86_get_al (c); s2 = e86_get_mem8 (c, seg, e86_get_di (c)); e86_set_di (c, e86_get_di (c) + inc); e86_set_cx (c, e86_get_cx (c) - 1); e86_set_flg_sub_8 (c, s1, s2); } e86_set_clk (c, 15); z = (c->prefix & E86_PREFIX_REP) ? 1 : 0; if ((e86_get_cx (c) == 0) || (e86_get_zf (c) != z)) { c->prefix &= ~E86_PREFIX_KEEP; return (1); } c->prefix |= E86_PREFIX_KEEP; return (0); } else { s1 = e86_get_al (c); s2 = e86_get_mem8 (c, seg, e86_get_di (c)); e86_set_di (c, e86_get_di (c) + inc); e86_set_flg_sub_8 (c, s1, s2); e86_set_clk (c, 15); } return (1); } /* Opcode AF: SCASW */ static unsigned op_af (e8086_t *c) { unsigned long s1, s2; unsigned short seg; unsigned short inc; int z; seg = e86_get_es (c); inc = e86_get_df (c) ? 0xfffe : 0x0002; if (c->prefix & (E86_PREFIX_REP | E86_PREFIX_REPN)) { if (e86_get_cx (c) != 0) { s1 = e86_get_ax (c); s2 = e86_get_mem16 (c, seg, e86_get_di (c)); e86_set_di (c, e86_get_di (c) + inc); e86_set_cx (c, e86_get_cx (c) - 1); e86_set_flg_sub_16 (c, s1, s2); } e86_set_clk (c, 15); z = (c->prefix & E86_PREFIX_REP) ? 1 : 0; if ((e86_get_cx (c) == 0) || (e86_get_zf (c) != z)) { c->prefix &= ~E86_PREFIX_KEEP; return (1); } c->prefix |= E86_PREFIX_KEEP; return (0); } else { s1 = e86_get_ax (c); s2 = e86_get_mem16 (c, seg, e86_get_di (c)); e86_set_di (c, e86_get_di (c) + inc); e86_set_flg_sub_16 (c, s1, s2); e86_set_clk (c, 15); } return (1); } /* OP B0: MOV AL, imm8 */ static unsigned op_b0 (e8086_t *c) { e86_set_al (c, c->pq[1]); e86_set_clk (c, 4); return (2); } /* OP B1: MOV CL, imm8 */ static unsigned op_b1 (e8086_t *c) { e86_set_cl (c, c->pq[1]); e86_set_clk (c, 4); return (2); } /* OP B2: MOV DL, imm8 */ static unsigned op_b2 (e8086_t *c) { e86_set_dl (c, c->pq[1]); e86_set_clk (c, 4); return (2); } /* OP B3: MOV BL, imm8 */ static unsigned op_b3 (e8086_t *c) { e86_set_bl (c, c->pq[1]); e86_set_clk (c, 4); return (2); } /* OP B4: MOV AH, imm8 */ static unsigned op_b4 (e8086_t *c) { e86_set_ah (c, c->pq[1]); e86_set_clk (c, 4); return (2); } /* OP B5: MOV CH, imm8 */ static unsigned op_b5 (e8086_t *c) { e86_set_ch (c, c->pq[1]); e86_set_clk (c, 4); return (2); } /* OP B6: MOV DH, imm8 */ static unsigned op_b6 (e8086_t *c) { e86_set_dh (c, c->pq[1]); e86_set_clk (c, 4); return (2); } /* OP B7: MOV BH, imm8 */ static unsigned op_b7 (e8086_t *c) { e86_set_bh (c, c->pq[1]); e86_set_clk (c, 4); return (2); } /* OP B8: MOV AX, imm16 */ static unsigned op_b8 (e8086_t *c) { e86_set_ax (c, e86_mk_uint16 (c->pq[1], c->pq[2])); e86_set_clk (c, 4); return (3); } /* OP B9: MOV CX, imm16 */ static unsigned op_b9 (e8086_t *c) { e86_set_cx (c, e86_mk_uint16 (c->pq[1], c->pq[2])); e86_set_clk (c, 4); return (3); } /* OP BA: MOV DX, imm16 */ static unsigned op_ba (e8086_t *c) { e86_set_dx (c, e86_mk_uint16 (c->pq[1], c->pq[2])); e86_set_clk (c, 4); return (3); } /* OP BB: MOV BX, imm16 */ static unsigned op_bb (e8086_t *c) { e86_set_bx (c, e86_mk_uint16 (c->pq[1], c->pq[2])); e86_set_clk (c, 4); return (3); } /* OP BC: MOV SP, imm16 */ static unsigned op_bc (e8086_t *c) { e86_set_sp (c, e86_mk_uint16 (c->pq[1], c->pq[2])); e86_set_clk (c, 4); return (3); } /* OP BD: MOV BP, imm16 */ static unsigned op_bd (e8086_t *c) { e86_set_bp (c, e86_mk_uint16 (c->pq[1], c->pq[2])); e86_set_clk (c, 4); return (3); } /* OP BE: MOV SI, imm16 */ static unsigned op_be (e8086_t *c) { e86_set_si (c, e86_mk_uint16 (c->pq[1], c->pq[2])); e86_set_clk (c, 4); return (3); } /* OP BF: MOV DI, imm16 */ static unsigned op_bf (e8086_t *c) { e86_set_di (c, e86_mk_uint16 (c->pq[1], c->pq[2])); e86_set_clk (c, 4); return (3); } /* OP C2: RET imm16 */ static unsigned op_c2 (e8086_t *c) { e86_set_ip (c, e86_pop (c)); e86_set_sp (c, e86_get_sp (c) + e86_mk_uint16 (c->pq[1], c->pq[2])); e86_pq_init (c); e86_set_clk (c, 20); return (0); } /* OP C3: RET */ static unsigned op_c3 (e8086_t *c) { e86_set_ip (c, e86_pop (c)); e86_pq_init (c); e86_set_clk (c, 16); return (0); } /* OP C4: LES reg16, r/m16 */ static unsigned op_c4 (e8086_t *c) { unsigned short val1, val2; e86_get_ea_ptr (c, c->pq + 1); if (c->ea.is_mem) { val1 = e86_get_mem16 (c, c->ea.seg, c->ea.ofs); val2 = e86_get_mem16 (c, c->ea.seg, c->ea.ofs + 2); e86_set_reg16 (c, (c->pq[1] >> 3) & 7, val1); e86_set_es (c, val2); e86_set_clk (c, 16); } return (c->ea.cnt + 1); } /* OP C5: LDS reg16, r/m16 */ static unsigned op_c5 (e8086_t *c) { unsigned short val1, val2; e86_get_ea_ptr (c, c->pq + 1); if (c->ea.is_mem) { val1 = e86_get_mem16 (c, c->ea.seg, c->ea.ofs); val2 = e86_get_mem16 (c, c->ea.seg, c->ea.ofs + 2); e86_set_reg16 (c, (c->pq[1] >> 3) & 7, val1); e86_set_ds (c, val2); e86_set_clk (c, 16); } return (c->ea.cnt + 1); } /* OP C6: MOV r/m8, data8 */ static unsigned op_c6 (e8086_t *c) { e86_get_ea_ptr (c, c->pq + 1); e86_set_ea8 (c, c->pq[c->ea.cnt + 1]); e86_set_clk_ea (c, 4, 10); return (c->ea.cnt + 2); } /* OP C7: MOV r/m16, data16 */ static unsigned op_c7 (e8086_t *c) { e86_get_ea_ptr (c, c->pq + 1); e86_set_ea16 (c, e86_mk_uint16 (c->pq[c->ea.cnt + 1], c->pq[c->ea.cnt + 2])); e86_set_clk_ea (c, 4, 10); return (c->ea.cnt + 3); } /* OP CA: RETF data16 */ static unsigned op_ca (e8086_t *c) { e86_set_ip (c, e86_pop (c)); e86_set_cs (c, e86_pop (c)); e86_set_sp (c, e86_get_sp (c) + e86_mk_uint16 (c->pq[1], c->pq[2])); e86_pq_init (c); e86_set_clk (c, 25); return (0); } /* OP CB: RETF */ static unsigned op_cb (e8086_t *c) { e86_set_ip (c, e86_pop (c)); e86_set_cs (c, e86_pop (c)); e86_pq_init (c); e86_set_clk (c, 26); return (0); } /* OP CC: INT 3 */ static unsigned op_cc (e8086_t *c) { if (c->trap != NULL) { if (c->trap (c->trap_ext, 3) == 0) { e86_set_clk (c, 4); return (1); } } e86_set_ip (c, e86_get_ip (c) + 1); e86_trap (c, 3); e86_pq_init (c); e86_set_clk (c, 52); return (0); } /* OP CD: INT imm8 */ static unsigned op_cd (e8086_t *c) { if (c->trap != NULL) { if (c->trap (c->trap_ext, c->pq[1]) == 0) { e86_set_clk (c, 4); return (2); } } e86_set_ip (c, e86_get_ip (c) + 2); e86_trap (c, c->pq[1]); e86_pq_init (c); e86_set_clk (c, 51); return (0); } /* OP CE: INTO */ static unsigned op_ce (e8086_t *c) { if (e86_get_of (c) == 0) { e86_set_clk (c, 4); return (1); } if (c->trap != NULL) { if (c->trap (c->trap_ext, 4) == 0) { e86_set_clk (c, 4); return (1); } } e86_set_ip (c, e86_get_ip (c) + 1); e86_trap (c, 4); e86_pq_init (c); e86_set_clk (c, 53); return (0); } /* OP CF: IRET */ static unsigned op_cf (e8086_t *c) { e86_set_ip (c, e86_pop (c)); e86_set_cs (c, e86_pop (c)); c->flg = e86_pop (c); e86_pq_init (c); e86_set_clk (c, 32); return (0); } /* OP D0: ROL, ROR, RCL, RCR, SHL, SHR, SAR r/m8, 1 */ static unsigned op_d0 (e8086_t *c) { unsigned xop; unsigned short d, s; xop = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s = e86_get_ea8 (c); switch (xop) { case 0: /* ROL r/m8, 1 */ d = (s << 1) | (s >> 7); e86_set_cf (c, s & 0x80); break; case 1: /* ROR r/m8, 1 */ d = (s >> 1) | (s << 7); e86_set_cf (c, s & 1); break; case 2: /* RCL r/m8, 1 */ d = (s << 1) | e86_get_cf (c); e86_set_cf (c, s & 0x80); break; case 3: /* RCR r/m8, 1 */ d = (s >> 1) | (e86_get_cf (c) << 7); e86_set_cf (c, s & 1); break; case 4: /* SHL r/m8, 1 */ d = s << 1; e86_set_flg_szp_8 (c, d); e86_set_cf (c, s & 0x80); break; case 5: /* SHR r/m8, 1 */ d = s >> 1; e86_set_flg_szp_8 (c, d); e86_set_cf (c, s & 1); break; case 7: /* SAR r/m8, 1 */ d = (s >> 1) | (s & 0x80); e86_set_flg_szp_8 (c, d); e86_set_cf (c, s & 1); break; default: return (op_ud (c)); } e86_set_of (c, (d ^ s) & 0x80); e86_set_ea8 (c, d & 0xff); e86_set_clk_ea (c, 2, 15); return (c->ea.cnt + 1); } /* OP D1: ROL, ROR, RCL, RCR, SHL, SHR, SAR r/m16, 1 */ static unsigned op_d1 (e8086_t *c) { unsigned xop; unsigned long d, s; xop = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s = e86_get_ea16 (c); switch (xop) { case 0: /* ROL r/m16, 1 */ d = (s << 1) | (s >> 15); e86_set_cf (c, s & 0x8000); break; case 1: /* ROR r/m16, 1 */ d = (s >> 1) | (s << 15); e86_set_cf (c, s & 1); break; case 2: /* RCL r/m16, 1 */ d = (s << 1) | e86_get_cf (c); e86_set_cf (c, s & 0x8000); break; case 3: /* RCR r/m16, 1 */ d = (s >> 1) | (e86_get_cf (c) << 15); e86_set_cf (c, s & 1); break; case 4: /* SHL r/m16, 1 */ d = s << 1; e86_set_flg_szp_16 (c, d); e86_set_cf (c, s & 0x8000); break; case 5: /* SHR r/m16, 1 */ d = s >> 1; e86_set_flg_szp_16 (c, d); e86_set_cf (c, s & 1); break; case 7: /* SAR r/m16, 1 */ d = (s >> 1) | (s & 0x8000); e86_set_flg_szp_16 (c, d); e86_set_cf (c, s & 1); break; default: return (op_ud (c)); } e86_set_of (c, (d ^ s) & 0x8000); e86_set_ea16 (c, d & 0xffff); e86_set_clk_ea (c, 2, 15); return (c->ea.cnt + 1); } /* OP D2: ROL, ROR, RCL, RCR, SHL, SHR, SAR r/m8, CL */ static unsigned op_d2 (e8086_t *c) { unsigned xop; unsigned cnt; unsigned short d, s; xop = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s = e86_get_ea8 (c); cnt = e86_get_cl (c); if (c->cpu & E86_CPU_MASK_SHIFT) { cnt &= 0x1f; } if (cnt == 0) { e86_set_clk_ea (c, 8, 20); return (c->ea.cnt + 1); } switch (xop) { case 0: /* ROL r/m8, CL */ d = (s << (cnt & 7)) | (s >> (8 - (cnt & 7))); e86_set_cf (c, d & 1); break; case 1: /* ROR r/m8, CL */ d = (s >> (cnt & 7)) | (s << (8 - (cnt & 7))); e86_set_cf (c, d & 0x80); break; case 2: /* RCL r/m8, CL */ s |= e86_get_cf (c) << 8; d = (s << (cnt % 9)) | (s >> (9 - (cnt % 9))); e86_set_cf (c, d & 0x100); break; case 3: /* RCR r/m8, CL */ s |= e86_get_cf (c) << 8; d = (s >> (cnt % 9)) | (s << (9 - (cnt % 9))); e86_set_cf (c, d & 0x100); break; case 4: /* SHL r/m8, CL */ d = (cnt > 8) ? 0 : (s << cnt); e86_set_flg_szp_8 (c, d); e86_set_cf (c, d & 0x100); break; case 5: /* SHR r/m8, CL */ d = (cnt > 8) ? 0 : (s >> (cnt - 1)); e86_set_cf (c, d & 1); d = d >> 1; e86_set_flg_szp_8 (c, d); break; case 7: /* SAR r/m8, CL */ s |= (s & 0x80) ? 0xff00 : 0x0000; d = s >> ((cnt >= 8) ? 7 : (cnt - 1)); e86_set_cf (c, d & 1); d = (d >> 1) & 0xff; e86_set_flg_szp_8 (c, d); break; default: return (op_ud (c)); } e86_set_of (c, (d ^ s) & 0x80); e86_set_ea8 (c, d & 0xff); e86_set_clk_ea (c, 8 + 4 * cnt, 20 + 4 * cnt); return (c->ea.cnt + 1); } /* OP D3: ROL, ROR, RCL, RCR, SHL, SHR, SAR r/m16, CL */ static unsigned op_d3 (e8086_t *c) { unsigned xop; unsigned cnt; unsigned long d, s; xop = (c->pq[1] >> 3) & 7; e86_get_ea_ptr (c, c->pq + 1); s = e86_get_ea16 (c); cnt = e86_get_cl (c); if (c->cpu & E86_CPU_MASK_SHIFT) { cnt &= 0x1f; } if (cnt == 0) { e86_set_clk_ea (c, 8, 20); return (c->ea.cnt + 1); } switch (xop) { case 0: /* ROL r/m16, CL */ d = (s << (cnt & 15)) | (s >> (16 - (cnt & 15))); e86_set_cf (c, d & 1); break; case 1: /* ROR r/m16, CL */ d = (s >> (cnt & 15)) | (s << (16 - (cnt & 15))); e86_set_cf (c, d & 0x8000); break; case 2: /* RCL r/m16, CL */ s |= (unsigned long) e86_get_cf (c) << 16; d = (s << (cnt % 17)) | (s >> (17 - (cnt % 17))); e86_set_cf (c, d & 0x10000); break; case 3: /* RCR r/m16, CL */ s |= (unsigned long) e86_get_cf (c) << 16; d = (s >> (cnt % 17)) | (s << (17 - (cnt % 17))); e86_set_cf (c, d & 0x10000); break; case 4: /* SHL r/m16, CL */ d = (cnt > 16) ? 0 : (s << cnt); e86_set_flg_szp_16 (c, d); e86_set_cf (c, d & 0x10000); break; case 5: /* SHR r/m16, CL */ d = (cnt > 16) ? 0 : (s >> (cnt - 1)); e86_set_cf (c, d & 1); d = d >> 1; e86_set_flg_szp_16 (c, d); break; case 7: /* SAR r/m16, CL */ s |= (s & 0x8000) ? 0xffff0000 : 0x00000000; d = s >> ((cnt >= 16) ? 15 : (cnt - 1)); e86_set_cf (c, d & 1); d = (d >> 1) & 0xffff; e86_set_flg_szp_16 (c, d); break; default: return (op_ud (c)); } e86_set_of (c, (d ^ s) & 0x8000); e86_set_ea16 (c, d); e86_set_clk_ea (c, 8 + 4 * cnt, 20 + 4 * cnt); return (c->ea.cnt + 1); } /* OP D4: AAM imm8 */ static unsigned op_d4 (e8086_t *c) { unsigned short s, d; unsigned short div; div = c->pq[1]; /* check for division by zero */ if (div == 0) { e86_trap (c, 0); return (0); } s = e86_get_al (c); d = (((s / div) & 0xff) << 8) | ((s % div) & 0xff); e86_set_ax (c, d); e86_set_flg_szp_16 (c, d); e86_set_clk (c, 83); return (2); } /* OP D5: AAD imm8 */ static unsigned op_d5 (e8086_t *c) { unsigned short s1, s2, d; unsigned short mul; mul = c->pq[1]; if (mul == 0) { if (e86_hook (c) == 0) { e86_set_clk (c, 4); return (2); } } s1 = e86_get_ah (c); s2 = e86_get_al (c); d = mul * s1 + s2; e86_set_ax (c, d & 0xff); e86_set_flg_szp_16 (c, d); e86_set_clk (c, 60); return (2); } /* OP D6: SALC */ static unsigned op_d6 (e8086_t *c) { unsigned short s1; s1 = e86_get_cf (c); e86_set_al (c, -s1); e86_set_clk (c, 3); return (1); } /* OP D7: XLAT */ static unsigned op_d7 (e8086_t *c) { unsigned short seg, ofs; seg = e86_get_seg (c, E86_REG_DS); ofs = e86_get_bx (c) + e86_get_al (c); e86_set_al (c, e86_get_mem8 (c, seg, ofs)); e86_set_clk (c, 11); return (1); } /* OP D8: ESC */ static unsigned op_d8 (e8086_t *c) { if (c->cpu & E86_CPU_INT7) { e86_trap (c, 7); e86_set_clk (c, 50); return (0); } e86_get_ea_ptr (c, c->pq + 1); e86_set_clk (c, 2); return (1 + c->ea.cnt); } /* OP E0: LOOPNZ imm8 */ static unsigned op_e0 (e8086_t *c) { e86_set_cx (c, e86_get_cx (c) - 1); if ((e86_get_cx (c) != 0) && (e86_get_zf (c) == 0)) { e86_set_ip (c, e86_add_sint8 (c->ip, c->pq[1]) + 2); e86_pq_init (c); e86_set_clk (c, 19); return (0); } e86_set_clk (c, 5); return (2); } /* OP E1: LOOPZ imm8 */ static unsigned op_e1 (e8086_t *c) { e86_set_cx (c, e86_get_cx (c) - 1); if ((e86_get_cx (c) != 0) && (e86_get_zf (c) != 0)) { e86_set_ip (c, e86_add_sint8 (c->ip, c->pq[1]) + 2); e86_pq_init (c); e86_set_clk (c, 18); return (0); } e86_set_clk (c, 5); return (2); } /* OP E2: LOOP imm8 */ static unsigned op_e2 (e8086_t *c) { e86_set_cx (c, e86_get_cx (c) - 1); if (e86_get_cx (c) != 0) { e86_set_ip (c, e86_add_sint8 (c->ip, c->pq[1]) + 2); e86_pq_init (c); e86_set_clk (c, 18); return (0); } e86_set_clk (c, 5); return (2); } /* OP E3: JCXZ imm8 */ static unsigned op_e3 (e8086_t *c) { if (e86_get_cx (c) == 0) { e86_set_ip (c, e86_add_sint8 (c->ip + 2, c->pq[1])); e86_pq_init (c); e86_set_clk (c, 18); return (0); } e86_set_clk (c, 6); return (2); } /* OP E4: IN AL, imm8 */ static unsigned op_e4 (e8086_t *c) { e86_set_al (c, e86_get_prt8 (c, c->pq[1])); e86_set_clk (c, 11); return (2); } /* OP E5: IN AX, imm8 */ static unsigned op_e5 (e8086_t *c) { e86_set_ax (c, e86_get_prt16 (c, c->pq[1])); e86_set_clk (c, 15); return (2); } /* OP E6: OUT imm8, AL */ static unsigned op_e6 (e8086_t *c) { e86_set_prt8 (c, c->pq[1], e86_get_al (c)); e86_set_clk (c, 11); return (2); } /* OP E7: OUT imm8, AX */ static unsigned op_e7 (e8086_t *c) { e86_set_prt16 (c, c->pq[1], e86_get_ax (c)); e86_set_clk (c, 11); return (2); } /* OP E8: CALL imm16 */ static unsigned op_e8 (e8086_t *c) { e86_push (c, e86_get_ip (c) + 3); e86_set_ip (c, e86_get_ip (c) + 3 + e86_mk_uint16 (c->pq[1], c->pq[2])); e86_pq_init (c); e86_set_clk (c, 19); return (0); } /* OP E9: JMP imm16 */ static unsigned op_e9 (e8086_t *c) { e86_set_ip (c, c->ip + e86_mk_uint16 (c->pq[1], c->pq[2]) + 3); e86_pq_init (c); e86_set_clk (c, 15); return (0); } /* OP EA: JMP imm32 */ static unsigned op_ea (e8086_t *c) { e86_set_ip (c, e86_mk_uint16 (c->pq[1], c->pq[2])); e86_set_cs (c, e86_mk_uint16 (c->pq[3], c->pq[4])); e86_pq_init (c); e86_set_clk (c, 15); return (0); } /* OP EB: JMP imm8 */ static unsigned op_eb (e8086_t *c) { e86_set_ip (c, e86_add_sint8 (c->ip, c->pq[1]) + 2); e86_pq_init (c); e86_set_clk (c, 15); return (0); } /* OP EC: IN AL, DX */ static unsigned op_ec (e8086_t *c) { e86_set_al (c, e86_get_prt8 (c, e86_get_dx (c))); e86_set_clk (c, 9); return (1); } /* OP ED: IN AX, DX */ static unsigned op_ed (e8086_t *c) { e86_set_ax (c, e86_get_prt16 (c, e86_get_dx (c))); e86_set_clk (c, 13); return (1); } /* OP EE: OUT DX, AL */ static unsigned op_ee (e8086_t *c) { e86_set_prt8 (c, e86_get_dx (c), e86_get_al (c)); e86_set_clk (c, 9); return (1); } /* OP EF: OUT DX, AX */ static unsigned op_ef (e8086_t *c) { e86_set_prt16 (c, e86_get_dx (c), e86_get_ax (c)); e86_set_clk (c, 9); return (1); } /* OP F0: LOCK */ static unsigned op_f0 (e8086_t *c) { c->prefix |= (E86_PREFIX_NEW | E86_PREFIX_LOCK); e86_set_clk (c, 2); return (1); } /* OP F2: REPNE */ static unsigned op_f2 (e8086_t *c) { c->prefix |= (E86_PREFIX_NEW | E86_PREFIX_REPN); e86_set_clk (c, 2); return (1); } /* OP F3: REP */ static unsigned op_f3 (e8086_t *c) { c->prefix |= (E86_PREFIX_NEW | E86_PREFIX_REP); e86_set_clk (c, 2); return (1); } /* OP F4: HLT */ static unsigned op_f4 (e8086_t *c) { c->state |= E86_STATE_HALT; e86_set_clk (c, 2); return (1); } /* OP F5: CMC */ static unsigned op_f5 (e8086_t *c) { c->flg ^= E86_FLG_C; e86_set_clk (c, 2); return (1); } /* OP F6 00: TEST r/m8, imm8 */ static unsigned op_f6_00 (e8086_t *c) { unsigned short s1, s2; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea8 (c); s2 = c->pq[c->ea.cnt + 1]; e86_set_flg_log_8 (c, s1 & s2); e86_set_clk_ea (c, 5, 11); return (c->ea.cnt + 2); } /* OP F6 02: NOT r/m8 */ static unsigned op_f6_02 (e8086_t *c) { unsigned short d, s; e86_get_ea_ptr (c, c->pq + 1); s = e86_get_ea8 (c); d = ~s & 0xff; e86_set_ea8 (c, d); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP F6 03: NEG r/m8 */ static unsigned op_f6_03 (e8086_t *c) { unsigned short d, s; e86_get_ea_ptr (c, c->pq + 1); s = e86_get_ea8 (c); d = (~s + 1) & 0xff; e86_set_ea8 (c, d); e86_set_flg_sub_8 (c, 0, s); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP F6 04: MUL r/m8 */ static unsigned op_f6_04 (e8086_t *c) { unsigned short d; e86_get_ea_ptr (c, c->pq + 1); d = e86_get_ea8 (c) * e86_get_al (c); e86_set_ax (c, d); e86_set_f (c, E86_FLG_O | E86_FLG_C, d & 0xff00); e86_set_f (c, E86_FLG_Z, d == 0); e86_set_clk_ea (c, (70 + 77) / 2, (76 + 83) / 2); return (c->ea.cnt + 1); } /* OP F6 05: IMUL r/m8 */ static unsigned op_f6_05 (e8086_t *c) { unsigned short s; unsigned long d; e86_get_ea_ptr (c, c->pq + 1); s = e86_get_ea8 (c); d = (unsigned long) e86_mk_sint16 (s); d *= (unsigned long) e86_mk_sint16 (e86_get_al (c)); d &= 0xffff; e86_set_ax (c, d); d &= 0xff80; e86_set_f (c, E86_FLG_C | E86_FLG_O, (d != 0xff80) && (d != 0x0000)); e86_set_clk_ea (c, (80 + 98) / 2, (86 + 104) / 2); return (c->ea.cnt + 1); } /* OP F6 06: DIV r/m8 */ static unsigned op_f6_06 (e8086_t *c) { unsigned short s, d; e86_get_ea_ptr (c, c->pq + 1); s = e86_get_ea8 (c); /* check for division by zero */ if (s == 0) { return (op_divide_error (c)); } d = e86_get_ax (c) / s; /* check for overflow */ if (d & 0xff00) { return (op_divide_error (c)); } e86_set_ax (c, ((e86_get_ax (c) % s) << 8) | d); e86_set_clk_ea (c, (80 + 90) / 2, (86 + 96) / 2); return (c->ea.cnt + 1); } /* OP F6 07: IDIV r/m8 */ static unsigned op_f6_07 (e8086_t *c) { unsigned short s1, s2, d1, d2; int sign1, sign2; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ax (c); s2 = e86_mk_sint16 (e86_get_ea8 (c)); /* check for division by zero */ if (s2 == 0) { return (op_divide_error (c)); } sign1 = (s1 & 0x8000) != 0; sign2 = (s2 & 0x8000) != 0; s1 = sign1 ? ((~s1 + 1) & 0xffff) : s1; s2 = sign2 ? ((~s2 + 1) & 0xffff) : s2; d1 = s1 / s2; d2 = s1 % s2; if (sign1 != sign2) { if (d1 > 0x80) { return (op_divide_error (c)); } d1 = (~d1 + 1) & 0xff; } else { if (d1 > 0x7f) { return (op_divide_error (c)); } } if (sign1) { d2 = (~d2 + 1) & 0xff; } e86_set_ax (c, (d2 << 8) | d1); e86_set_clk_ea (c, (101 + 112) / 2, (107 + 118) / 2); return (c->ea.cnt + 1); } static e86_opcode_f e86_opcodes_f6[8] = { &op_f6_00, &op_ud, &op_f6_02, &op_f6_03, &op_f6_04, &op_f6_05, &op_f6_06, &op_f6_07, }; /* OP F6: xxx r/m8 */ static unsigned op_f6 (e8086_t *c) { unsigned xop; xop = (c->pq[1] >> 3) & 7; return (e86_opcodes_f6[xop] (c)); } /* OP F7 00: TEST r/m16, imm16 */ static unsigned op_f7_00 (e8086_t *c) { unsigned long s1, s2; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ea16 (c); s2 = e86_mk_uint16 (c->pq[c->ea.cnt + 1], c->pq[c->ea.cnt + 2]); e86_set_flg_log_16 (c, s1 & s2); e86_set_clk_ea (c, 5, 11); return (c->ea.cnt + 3); } /* OP F7 02: NOT r/m16 */ static unsigned op_f7_02 (e8086_t *c) { unsigned long d, s; e86_get_ea_ptr (c, c->pq + 1); s = e86_get_ea16 (c); d = ~s & 0xffff; e86_set_ea16 (c, d); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP F7 03: NEG r/m16 */ static unsigned op_f7_03 (e8086_t *c) { unsigned long d, s; e86_get_ea_ptr (c, c->pq + 1); s = e86_get_ea16 (c); d = (~s + 1) & 0xffff; e86_set_ea16 (c, d); e86_set_flg_sub_16 (c, 0, s); e86_set_clk_ea (c, 3, 16); return (c->ea.cnt + 1); } /* OP F7 04: MUL r/m16 */ static unsigned op_f7_04 (e8086_t *c) { unsigned long d; e86_get_ea_ptr (c, c->pq + 1); d = e86_get_ea16 (c) * e86_get_ax (c); e86_set_ax (c, d & 0xffff); e86_set_dx (c, d >> 16); e86_set_f (c, E86_FLG_C | E86_FLG_O, d & 0xffff0000); e86_set_f (c, E86_FLG_Z, d == 0); e86_set_clk_ea (c, (118 + 113) / 2, (124 + 139) / 2); return (c->ea.cnt + 1); } /* OP F7 05: IMUL r/m16 */ static unsigned op_f7_05 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s1 = e86_get_ax (c); s2 = e86_get_ea16 (c); s1 = (s1 & 0x8000) ? (s1 | 0xffff0000) : s1; s2 = (s2 & 0x8000) ? (s2 | 0xffff0000) : s2; d = (s1 * s2) & 0xffffffff; e86_set_ax (c, d & 0xffff); e86_set_dx (c, d >> 16); d &= 0xffff8000; e86_set_f (c, E86_FLG_C | E86_FLG_O, (d != 0xffff8000) && (d != 0x00000000)); e86_set_clk_ea (c, (128 + 154) / 2, (134 + 160) / 2); return (c->ea.cnt + 1); } /* OP F7 06: DIV r/m16 */ static unsigned op_f7_06 (e8086_t *c) { unsigned long s1, s2, d; e86_get_ea_ptr (c, c->pq + 1); s2 = e86_get_ea16 (c); /* check for division by zero */ if (s2 == 0) { return (op_divide_error (c)); } s1 = ((unsigned long) e86_get_dx (c) << 16) | e86_get_ax (c); d = s1 / s2; /* check for overflow */ if (d & 0xffff0000) { return (op_divide_error (c)); } e86_set_ax (c, d); e86_set_dx (c, s1 % s2); e86_set_clk_ea (c, (144 + 162) / 2, (150 + 168) / 2); return (c->ea.cnt + 1); } /* OP F7 07: IDIV r/m16 */ static unsigned op_f7_07 (e8086_t *c) { unsigned long s1, s2, d1, d2; int sign1, sign2; e86_get_ea_ptr (c, c->pq + 1); s1 = ((unsigned long) e86_get_dx (c) << 16) | e86_get_ax (c); s2 = e86_get_ea16 (c); s2 = (s2 & 0x8000) ? (s2 | 0xffff0000) : s2; if (s2 == 0) { return (op_divide_error (c)); } sign1 = (s1 & 0x80000000) != 0; sign2 = (s2 & 0x80000000) != 0; s1 = sign1 ? ((~s1 + 1) & 0xffffffff) : s1; s2 = sign2 ? ((~s2 + 1) & 0xffffffff) : s2; d1 = s1 / s2; d2 = s1 % s2; if (sign1 != sign2) { if (d1 > 0x8000) { return (op_divide_error (c)); } d1 = (~d1 + 1) & 0xffff; } else { if (d1 > 0x7fff) { return (op_divide_error (c)); } } if (sign1) { d2 = (~d2 + 1) & 0xffff; } e86_set_ax (c, d1); e86_set_dx (c, d2); e86_set_clk_ea (c, (165 + 184) / 2, (171 + 190) / 2); return (c->ea.cnt + 1); } static e86_opcode_f e86_opcodes_f7[8] = { &op_f7_00, &op_ud, &op_f7_02, &op_f7_03, &op_f7_04, &op_f7_05, &op_f7_06, &op_f7_07, }; /* OP F7: xxx r/m16 */ static unsigned op_f7 (e8086_t *c) { unsigned xop; xop = (c->pq[1] >> 3) & 7; return (e86_opcodes_f7[xop] (c)); } /* OP F8: CLC */ static unsigned op_f8 (e8086_t *c) { e86_set_cf (c, 0); e86_set_clk (c, 2); return (1); } /* OP F9: STC */ static unsigned op_f9 (e8086_t *c) { e86_set_cf (c, 1); e86_set_clk (c, 2); return (1); } /* OP FA: CLI */ static unsigned op_fa (e8086_t *c) { e86_set_if (c, 0); e86_set_clk (c, 2); return (1); } /* OP FB: STI */ static unsigned op_fb (e8086_t *c) { e86_set_if (c, 1); e86_set_clk (c, 2); return (1); } /* OP FC: CLD */ static unsigned op_fc (e8086_t *c) { e86_set_df (c, 0); e86_set_clk (c, 2); return (1); } /* OP FD: STD */ static unsigned op_fd (e8086_t *c) { e86_set_df (c, 1); e86_set_clk (c, 2); return (1); } /* OP FE: INC, DEC r/m8 */ static unsigned op_fe (e8086_t *c) { unsigned xop; unsigned short d, s; unsigned short cf; xop = (c->pq[1] >> 3) & 7; switch (xop) { case 0: /* INC r/m8 */ e86_get_ea_ptr (c, c->pq + 1); s = e86_get_ea8 (c); d = s + 1; e86_set_ea8 (c, d); cf = c->flg; e86_set_flg_add_8 (c, s, 1); c->flg ^= (c->flg ^ cf) & E86_FLG_C; e86_set_clk_ea (c, 3, 15); return (c->ea.cnt + 1); case 1: /* DEC r/m8 */ e86_get_ea_ptr (c, c->pq + 1); s = e86_get_ea8 (c); d = s - 1; e86_set_ea8 (c, d); cf = c->flg; e86_set_flg_sub_8 (c, s, 1); c->flg ^= (c->flg ^ cf) & E86_FLG_C; e86_set_clk_ea (c, 3, 15); return (c->ea.cnt + 1); default: return (op_ud (c)); } return (0); } /* OP FF 00: INC r/m16 */ static unsigned op_ff_00 (e8086_t *c) { unsigned long s, d; unsigned short cf; e86_get_ea_ptr (c, c->pq + 1); s = e86_get_ea16 (c); d = s + 1; e86_set_ea16 (c, d); cf = c->flg; e86_set_flg_add_16 (c, s, 1); c->flg ^= (c->flg ^ cf) & E86_FLG_C; e86_set_clk_ea (c, 3, 15); return (c->ea.cnt + 1); } /* OP FF 01: DEC r/m16 */ static unsigned op_ff_01 (e8086_t *c) { unsigned long s, d; unsigned short cf; e86_get_ea_ptr (c, c->pq + 1); s = e86_get_ea16 (c); d = s - 1; e86_set_ea16 (c, d); cf = c->flg; e86_set_flg_sub_16 (c, s, 1); c->flg ^= (c->flg ^ cf) & E86_FLG_C; e86_set_clk_ea (c, 3, 15); return (c->ea.cnt + 1); } /* OP FF 02: CALL r/m16 */ static unsigned op_ff_02 (e8086_t *c) { e86_get_ea_ptr (c, c->pq + 1); e86_push (c, e86_get_ip (c) + c->ea.cnt + 1); e86_set_ip (c, e86_get_ea16 (c)); e86_pq_init (c); e86_set_clk_ea (c, 16, 21); return (0); } /* OP FF 03: CALL m32 */ static unsigned op_ff_03 (e8086_t *c) { unsigned short seg, ofs; e86_get_ea_ptr (c, c->pq + 1); if (!c->ea.is_mem) { return (c->ea.cnt + 1); } e86_push (c, e86_get_cs (c)); e86_push (c, e86_get_ip (c) + c->ea.cnt + 1); seg = e86_get_sego (c, c->ea.seg); ofs = c->ea.ofs; e86_set_ip (c, e86_get_mem16 (c, seg, ofs)); e86_set_cs (c, e86_get_mem16 (c, seg, ofs + 2)); e86_pq_init (c); e86_set_clk (c, 37); return (0); } /* OP FF 04: JMP r/m16 */ static unsigned op_ff_04 (e8086_t *c) { e86_get_ea_ptr (c, c->pq + 1); e86_set_ip (c, e86_get_ea16 (c)); e86_pq_init (c); e86_set_clk_ea (c, 11, 18); return (0); } /* OP FF 05: JMP m32 */ static unsigned op_ff_05 (e8086_t *c) { e86_get_ea_ptr (c, c->pq + 1); if (!c->ea.is_mem) { return (c->ea.cnt + 1); } e86_set_ip (c, e86_get_mem16 (c, c->ea.seg, c->ea.ofs)); e86_set_cs (c, e86_get_mem16 (c, c->ea.seg, c->ea.ofs + 2)); e86_pq_init (c); e86_set_clk (c, 24); return (0); } /* OP FF 06: PUSH r/m16 */ static unsigned op_ff_06 (e8086_t *c) { e86_get_ea_ptr (c, c->pq + 1); if ((c->ea.is_mem == 0) && (c->ea.ofs == E86_REG_SP) && ((c->cpu & E86_CPU_PUSH_FIRST) == 0)) { e86_push (c, e86_get_sp (c) - 2); } else { e86_push (c, e86_get_ea16 (c)); } e86_set_clk_ea (c, 10, 16); return (c->ea.cnt + 1); } static e86_opcode_f e86_opcodes_ff[8] = { &op_ff_00, &op_ff_01, &op_ff_02, &op_ff_03, &op_ff_04, &op_ff_05, &op_ff_06, &op_ud }; /* OP FF: xxx r/m16 */ static unsigned op_ff (e8086_t *c) { unsigned xop; xop = (c->pq[1] >> 3) & 7; return (e86_opcodes_ff[xop] (c)); } e86_opcode_f e86_opcodes[256] = { &op_00, &op_01, &op_02, &op_03, &op_04, &op_05, &op_06, &op_07, &op_08, &op_09, &op_0a, &op_0b, &op_0c, &op_0d, &op_0e, &op_0f, &op_10, &op_11, &op_12, &op_13, &op_14, &op_15, &op_16, &op_17, &op_18, &op_19, &op_1a, &op_1b, &op_1c, &op_1d, &op_1e, &op_1f, &op_20, &op_21, &op_22, &op_23, &op_24, &op_25, &op_26, &op_27, /* 20 */ &op_28, &op_29, &op_2a, &op_2b, &op_2c, &op_2d, &op_2e, &op_2f, &op_30, &op_31, &op_32, &op_33, &op_34, &op_35, &op_36, &op_37, /* 30 */ &op_38, &op_39, &op_3a, &op_3b, &op_3c, &op_3d, &op_3e, &op_3f, &op_40, &op_40, &op_40, &op_40, &op_40, &op_40, &op_40, &op_40, /* 40 */ &op_48, &op_48, &op_48, &op_48, &op_48, &op_48, &op_48, &op_48, &op_50, &op_50, &op_50, &op_50, &op_50, &op_50, &op_50, &op_50, /* 50 */ &op_58, &op_58, &op_58, &op_58, &op_58, &op_58, &op_58, &op_58, &op_ud, &op_ud, &op_ud, &op_ud, &op_ud, &op_ud, &op_66, &op_ud, /* 60 */ &op_ud, &op_ud, &op_ud, &op_ud, &op_ud, &op_ud, &op_ud, &op_ud, &op_70, &op_71, &op_72, &op_73, &op_74, &op_75, &op_76, &op_77, /* 70 */ &op_78, &op_79, &op_7a, &op_7b, &op_7c, &op_7d, &op_7e, &op_7f, &op_80, &op_81, &op_80, &op_83, &op_84, &op_85, &op_86, &op_87, /* 80 */ &op_88, &op_89, &op_8a, &op_8b, &op_8c, &op_8d, &op_8e, &op_8f, &op_90, &op_90, &op_90, &op_90, &op_90, &op_90, &op_90, &op_90, /* 90 */ &op_98, &op_99, &op_9a, &op_9b, &op_9c, &op_9d, &op_9e, &op_9f, &op_a0, &op_a1, &op_a2, &op_a3, &op_a4, &op_a5, &op_a6, &op_a7, /* A0 */ &op_a8, &op_a9, &op_aa, &op_ab, &op_ac, &op_ad, &op_ae, &op_af, &op_b0, &op_b1, &op_b2, &op_b3, &op_b4, &op_b5, &op_b6, &op_b7, /* B0 */ &op_b8, &op_b9, &op_ba, &op_bb, &op_bc, &op_bd, &op_be, &op_bf, &op_ud, &op_ud, &op_c2, &op_c3, &op_c4, &op_c5, &op_c6, &op_c7, /* C0 */ &op_ud, &op_ud, &op_ca, &op_cb, &op_cc, &op_cd, &op_ce, &op_cf, &op_d0, &op_d1, &op_d2, &op_d3, &op_d4, &op_d5, &op_d6, &op_d7, /* D0 */ &op_d8, &op_d8, &op_d8, &op_d8, &op_d8, &op_d8, &op_d8, &op_d8, &op_e0, &op_e1, &op_e2, &op_e3, &op_e4, &op_e5, &op_e6, &op_e7, /* E0 */ &op_e8, &op_e9, &op_ea, &op_eb, &op_ec, &op_ed, &op_ee, &op_ef, &op_f0, &op_ud, &op_f2, &op_f3, &op_f4, &op_f5, &op_f6, &op_f7, /* F0 */ &op_f8, &op_f9, &op_fa, &op_fb, &op_fc, &op_fd, &op_fe, &op_ff };