4746 lines
168 KiB
C
4746 lines
168 KiB
C
/* 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);
|
|
}
|