mirror of
https://github.com/86Box/86Box.git
synced 2026-02-23 09:58:19 -07:00
4784 lines
138 KiB
C
4784 lines
138 KiB
C
/*
|
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
* running old operating systems and software designed for IBM
|
|
* PC systems and compatibles from 1981 through fairly recent
|
|
* system designs based on the PCI bus.
|
|
*
|
|
* This file is part of the 86Box distribution.
|
|
*
|
|
* 808x CPU emulation, mostly ported from reenigne's XTCE, which
|
|
* is cycle-accurate.
|
|
*
|
|
* Authors: Andrew Jenner, <https://www.reenigne.org>
|
|
* Miran Grca, <mgrca8@gmail.com>
|
|
*
|
|
* Copyright 2015-2020 Andrew Jenner.
|
|
* Copyright 2016-2020 Miran Grca.
|
|
*/
|
|
#include <math.h>
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <wchar.h>
|
|
|
|
#include "i8080.h"
|
|
|
|
#define HAVE_STDARG_H
|
|
#include <86box/86box.h>
|
|
#include "cpu.h"
|
|
#include "x86.h"
|
|
#include <86box/machine.h>
|
|
#include <86box/io.h>
|
|
#include <86box/mem.h>
|
|
#include <86box/rom.h>
|
|
#include <86box/nmi.h>
|
|
#include <86box/pic.h>
|
|
#include <86box/ppi.h>
|
|
#include <86box/timer.h>
|
|
#include <86box/gdbstub.h>
|
|
#include <86box/plat_fallthrough.h>
|
|
#include <86box/plat_unused.h>
|
|
#include "vx0_biu.h"
|
|
|
|
#define do_cycle() wait(1)
|
|
#define do_cycle_no_modrm() if (!nx) \
|
|
do_cycle()
|
|
#define do_cycle_i() do_cycle()
|
|
#define do_cycles(c) wait(c)
|
|
#define do_cycles_i(c) do_cycles(c)
|
|
#define do_cycle_nx() nx = 1
|
|
#define do_cycle_nx_i() nx = 1
|
|
#define do_cycles_nx(c) nx = 1; \
|
|
if (c > 1) \
|
|
do_cycles(c - 1)
|
|
#define do_cycles_nx_i(c) nx = 1; \
|
|
if (c > 1) \
|
|
do_cycles(c - 1)
|
|
#define addr_mode_match() cpu_mod == 3
|
|
#define math_op(o) cpu_alu_op = o; \
|
|
alu_op(bits)
|
|
|
|
/* Various things needed for 8087. */
|
|
#define OP_TABLE(name) ops_##name
|
|
|
|
#define CPU_BLOCK_END()
|
|
#define SEG_CHECK_READ(seg)
|
|
#define SEG_CHECK_WRITE(seg)
|
|
#define CHECK_READ(a, b, c)
|
|
#define CHECK_WRITE(a, b, c)
|
|
#define UN_USED(x) (void) (x)
|
|
#define fetch_ea_16(val)
|
|
#define fetch_ea_32(val)
|
|
#define PREFETCH_RUN(a, b, c, d, e, f, g, h)
|
|
|
|
#define CYCLES(val) \
|
|
{ \
|
|
do_cycles(val); \
|
|
}
|
|
|
|
#define CLOCK_CYCLES_ALWAYS(val) \
|
|
{ \
|
|
do_cycles(val); \
|
|
}
|
|
|
|
#define CLOCK_CYCLES_FPU(val) \
|
|
{ \
|
|
do_cycles(val); \
|
|
}
|
|
|
|
# define CLOCK_CYCLES(val) \
|
|
{ \
|
|
if (fpu_cycles > 0) { \
|
|
fpu_cycles -= (val); \
|
|
if (fpu_cycles < 0) { \
|
|
do_cycles(val); \
|
|
} \
|
|
} else { \
|
|
do_cycles(val); \
|
|
} \
|
|
}
|
|
|
|
#define CONCURRENCY_CYCLES(c) fpu_cycles = (c)
|
|
|
|
#define OP_MRM 1
|
|
#define OP_EA 2
|
|
#define OP_MEA (OP_MRM | OP_EA)
|
|
#define OP_GRP 4
|
|
#define OP_DELAY 8
|
|
#define OP_PRE 16
|
|
|
|
#define readmemb readmemb_vx0
|
|
#define readmemw readmemw_vx0
|
|
#define readmem readmem_vx0
|
|
#define readmeml readmeml_vx0
|
|
#define readmemq readmemq_vx0
|
|
#define writememb writememb_vx0
|
|
#define writememw writememw_vx0
|
|
#define writemem writemem_vx0
|
|
#define writememl writememl_vx0
|
|
#define writememq writememq_vx0
|
|
|
|
typedef int (*OpFn)(uint32_t fetchdat);
|
|
|
|
static void farret(int far);
|
|
|
|
const uint8_t opf[256] = { OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, 0, /* 00 */
|
|
OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, 0, /* 08 */
|
|
OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, 0, /* 10 */
|
|
OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, 0, /* 18 */
|
|
OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 20 */
|
|
OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 28 */
|
|
OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 30 */
|
|
OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 38 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 40 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 48 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 50 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 58 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 60 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 68 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 70 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 78 */
|
|
OP_GRP, OP_GRP, OP_GRP, OP_GRP, OP_MEA, OP_MEA, OP_MEA, OP_MEA, /* 80 */
|
|
OP_MRM, OP_MRM, OP_MEA, OP_MEA, OP_MRM, OP_MRM, OP_MEA, OP_MRM, /* 88 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 90 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 98 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* A0 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* A8 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* B0 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* B8 */
|
|
0, 0, 0, 0, OP_MEA, OP_MEA, OP_MRM, OP_MRM, /* C0 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* C8 */
|
|
OP_GRP, OP_GRP, OP_GRP, OP_GRP, 0, 0, 0, 0, /* D0 */
|
|
OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, /* D8 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* E0 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* E8 */
|
|
OP_PRE, OP_PRE, OP_PRE, OP_PRE, 0, 0, OP_GRP, OP_GRP, /* F0 */
|
|
0, 0, 0, 0, 0, 0, OP_GRP, OP_GRP }; /* F8 */
|
|
|
|
const uint8_t opf_nec[256] = { OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, 0, /* 00 */
|
|
OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, OP_PRE, /* 08 */
|
|
OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, 0, /* 10 */
|
|
OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, 0, /* 18 */
|
|
OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 20 */
|
|
OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 28 */
|
|
OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 30 */
|
|
OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 38 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 40 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 48 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 50 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 58 */
|
|
0, 0, OP_MRM, OP_MRM, OP_PRE, OP_PRE, OP_MRM, OP_MRM, /* 60 */
|
|
0, OP_MRM, 0, OP_MEA, 0, 0, 0, 0, /* 68 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 70 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 78 */
|
|
OP_GRP, OP_GRP, OP_GRP, OP_GRP, OP_MEA, OP_MEA, OP_MEA, OP_MEA, /* 80 */
|
|
OP_MRM, OP_MRM, OP_MEA, OP_MEA, OP_MRM, OP_MRM, OP_MEA, OP_MRM, /* 88 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 90 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 98 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* A0 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* A8 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* B0 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* B8 */
|
|
OP_GRP, OP_GRP, 0, 0, OP_MEA, OP_MEA, OP_MRM, OP_MRM, /* C0 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* C8 */
|
|
OP_GRP, OP_GRP, OP_GRP, OP_GRP, 0, 0, 0, 0, /* D0 */
|
|
OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, /* D8 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* E0 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* E8 */
|
|
OP_PRE, OP_PRE, OP_PRE, OP_PRE, 0, 0, OP_GRP, OP_GRP, /* F0 */
|
|
0, 0, 0, 0, 0, 0, OP_GRP, OP_GRP }; /* F8 */
|
|
|
|
const uint8_t opf_0f[256] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 08 */
|
|
OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, /* 10 */
|
|
OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, /* 18 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 20 */
|
|
OP_MRM, 0, OP_MRM, 0, 0, 0, 0, 0, /* 28 */
|
|
OP_MRM, 0, OP_MRM, 0, 0, 0, 0, 0, /* 30 */
|
|
OP_MRM, 0, OP_MRM, 0, 0, 0, 0, 0, /* 38 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 40 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 48 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 50 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 58 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 60 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 68 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 70 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 78 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 80 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 88 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 90 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* 98 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* A0 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* A8 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* B0 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* B8 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* C0 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* C8 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* D0 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* D8 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* E0 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* E8 */
|
|
0, 0, 0, 0, 0, 0, 0, 0, /* F0 */
|
|
0, 0, 0, 0, 0, 0, 0, 0 }; /* F8 */
|
|
|
|
uint8_t use_custom_nmi_vector = 0;
|
|
|
|
uint32_t custom_nmi_vector = 0x00000000;
|
|
|
|
/* Is the CPU 8088 or 8086. */
|
|
int is8086 = 0;
|
|
int nx = 0;
|
|
|
|
static uint32_t cpu_src = 0;
|
|
static uint32_t cpu_dest = 0;
|
|
|
|
static uint32_t cpu_data = 0;
|
|
|
|
static int oldc;
|
|
static int cpu_alu_op;
|
|
static int completed = 1;
|
|
static int in_rep = 0;
|
|
static int repeating = 0;
|
|
static int rep_c_flag = 0;
|
|
static int clear_lock = 0;
|
|
static int noint = 0;
|
|
static int tempc_fpu = 0;
|
|
static int started = 0;
|
|
static int group_delay = 0;
|
|
static int modrm_loaded = 0;
|
|
static int in_0f = 0;
|
|
static int in_hlt = 0;
|
|
static int retem = 0;
|
|
static int halted = 0;
|
|
|
|
static uint32_t * ovr_seg = NULL;
|
|
|
|
/* Pointer tables needed for segment overrides. */
|
|
static uint32_t * opseg[4];
|
|
|
|
static x86seg * _opseg[4];
|
|
|
|
enum {
|
|
MODRM_ADDR_BX_SI = 0x00,
|
|
MODRM_ADDR_BX_DI,
|
|
MODRM_ADDR_BP_SI,
|
|
MODRM_ADDR_BP_DI,
|
|
MODRM_ADDR_SI,
|
|
MODRM_ADDR_DI,
|
|
MODRM_ADDR_DISP16,
|
|
MODRM_ADDR_BX,
|
|
|
|
MODRM_ADDR_BX_SI_DISP8 = 0x40,
|
|
MODRM_ADDR_BX_DI_DISP8,
|
|
MODRM_ADDR_BP_SI_DISP8,
|
|
MODRM_ADDR_BP_DI_DISP8,
|
|
MODRM_ADDR_SI_DISP8,
|
|
MODRM_ADDR_DI_DISP8,
|
|
MODRM_ADDR_BP_DISP8,
|
|
MODRM_ADDR_BX_DISP8,
|
|
|
|
MODRM_ADDR_BX_SI_DISP16 = 0x80,
|
|
MODRM_ADDR_BX_DI_DISP16,
|
|
MODRM_ADDR_BP_SI_DISP16,
|
|
MODRM_ADDR_BP_DI_DISP16,
|
|
MODRM_ADDR_SI_DISP16,
|
|
MODRM_ADDR_DI_DISP16,
|
|
MODRM_ADDR_BP_DISP16,
|
|
MODRM_ADDR_BX_DISP16
|
|
};
|
|
|
|
static uint8_t modrm_cycs_pre[256] = { [MODRM_ADDR_BX_SI] = 4,
|
|
[MODRM_ADDR_BX_DI] = 5,
|
|
[MODRM_ADDR_BP_SI] = 5,
|
|
[MODRM_ADDR_BP_DI] = 4,
|
|
[MODRM_ADDR_SI] = 2,
|
|
[MODRM_ADDR_DI] = 2,
|
|
[MODRM_ADDR_DISP16] = 0,
|
|
[MODRM_ADDR_BX] = 2,
|
|
[0x08 ... 0x3f] = 0,
|
|
[MODRM_ADDR_BX_SI_DISP8] = 4,
|
|
[MODRM_ADDR_BX_DI_DISP8] = 5,
|
|
[MODRM_ADDR_BP_SI_DISP8] = 5,
|
|
[MODRM_ADDR_BP_DI_DISP8] = 4,
|
|
[MODRM_ADDR_SI_DISP8] = 2,
|
|
[MODRM_ADDR_DI_DISP8] = 2,
|
|
[MODRM_ADDR_BP_DISP8] = 2,
|
|
[MODRM_ADDR_BX_DISP8] = 2,
|
|
[0x48 ... 0x7f] = 0,
|
|
[MODRM_ADDR_BX_SI_DISP16] = 4,
|
|
[MODRM_ADDR_BX_DI_DISP16] = 5,
|
|
[MODRM_ADDR_BP_SI_DISP16] = 5,
|
|
[MODRM_ADDR_BP_DI_DISP16] = 4,
|
|
[MODRM_ADDR_SI_DISP16] = 2,
|
|
[MODRM_ADDR_DI_DISP16] = 2,
|
|
[MODRM_ADDR_BP_DISP16] = 2,
|
|
[MODRM_ADDR_BX_DISP16] = 2,
|
|
[0x88 ... 0xff] = 0 };
|
|
|
|
static uint8_t modrm_cycs_post[256] = { [MODRM_ADDR_BX_SI] = 0,
|
|
[MODRM_ADDR_BX_DI] = 0,
|
|
[MODRM_ADDR_BP_SI] = 0,
|
|
[MODRM_ADDR_BP_DI] = 0,
|
|
[MODRM_ADDR_SI] = 0,
|
|
[MODRM_ADDR_DI] = 0,
|
|
[MODRM_ADDR_DISP16] = 1,
|
|
[MODRM_ADDR_BX] = 0,
|
|
[0x08 ... 0x3f] = 0,
|
|
[MODRM_ADDR_BX_SI_DISP8] = 3,
|
|
[MODRM_ADDR_BX_DI_DISP8] = 3,
|
|
[MODRM_ADDR_BP_SI_DISP8] = 3,
|
|
[MODRM_ADDR_BP_DI_DISP8] = 3,
|
|
[MODRM_ADDR_SI_DISP8] = 3,
|
|
[MODRM_ADDR_DI_DISP8] = 3,
|
|
[MODRM_ADDR_BP_DISP8] = 3,
|
|
[MODRM_ADDR_BX_DISP8] = 3,
|
|
[0x48 ... 0x7f] = 0,
|
|
[MODRM_ADDR_BX_SI_DISP16] = 2,
|
|
[MODRM_ADDR_BX_DI_DISP16] = 2,
|
|
[MODRM_ADDR_BP_SI_DISP16] = 2,
|
|
[MODRM_ADDR_BP_DI_DISP16] = 2,
|
|
[MODRM_ADDR_SI_DISP16] = 2,
|
|
[MODRM_ADDR_DI_DISP16] = 2,
|
|
[MODRM_ADDR_BP_DISP16] = 2,
|
|
[MODRM_ADDR_BX_DISP16] = 2,
|
|
[0x88 ... 0xff] = 0 };
|
|
|
|
#ifdef ENABLE_808X_LOG
|
|
#if 0
|
|
void dumpregs(int);
|
|
#endif
|
|
int x808x_do_log = ENABLE_808X_LOG;
|
|
|
|
static void
|
|
x808x_log(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (x808x_do_log) {
|
|
va_start(ap, fmt);
|
|
pclog_ex(fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
}
|
|
#else
|
|
# define x808x_log(fmt, ...)
|
|
#endif
|
|
|
|
static i8080 emulated_processor;
|
|
static bool cpu_md_write_disable = 1;
|
|
|
|
static void
|
|
set_if(int cond)
|
|
{
|
|
cpu_state.flags = (cpu_state.flags & ~I_FLAG) | (cond ? I_FLAG : 0);
|
|
}
|
|
|
|
void
|
|
sync_from_i8080(void)
|
|
{
|
|
AL = emulated_processor.a;
|
|
BH = emulated_processor.h;
|
|
BL = emulated_processor.l;
|
|
CH = emulated_processor.b;
|
|
CL = emulated_processor.c;
|
|
DH = emulated_processor.d;
|
|
DL = emulated_processor.e;
|
|
BP = emulated_processor.sp;
|
|
|
|
cpu_state.pc = emulated_processor.pc;
|
|
cpu_state.flags &= 0xFF00;
|
|
cpu_state.flags |= emulated_processor.sf << 7;
|
|
cpu_state.flags |= emulated_processor.zf << 6;
|
|
cpu_state.flags |= emulated_processor.hf << 4;
|
|
cpu_state.flags |= emulated_processor.pf << 2;
|
|
cpu_state.flags |= 1 << 1;
|
|
cpu_state.flags |= emulated_processor.cf << 0;
|
|
set_if(emulated_processor.iff);
|
|
}
|
|
|
|
void
|
|
sync_to_i8080(void)
|
|
{
|
|
if (!is_nec)
|
|
return;
|
|
emulated_processor.a = AL;
|
|
emulated_processor.h = BH;
|
|
emulated_processor.l = BL;
|
|
emulated_processor.b = CH;
|
|
emulated_processor.c = CL;
|
|
emulated_processor.d = DH;
|
|
emulated_processor.e = DL;
|
|
emulated_processor.sp = BP;
|
|
emulated_processor.pc = cpu_state.pc;
|
|
emulated_processor.iff = !!(cpu_state.flags & I_FLAG);
|
|
|
|
emulated_processor.sf = (cpu_state.flags >> 7) & 1;
|
|
emulated_processor.zf = (cpu_state.flags >> 6) & 1;
|
|
emulated_processor.hf = (cpu_state.flags >> 4) & 1;
|
|
emulated_processor.pf = (cpu_state.flags >> 2) & 1;
|
|
emulated_processor.cf = (cpu_state.flags >> 0) & 1;
|
|
|
|
emulated_processor.interrupt_delay = noint;
|
|
}
|
|
|
|
uint16_t
|
|
get_last_addr(void)
|
|
{
|
|
return last_addr;
|
|
}
|
|
|
|
static void
|
|
set_ip(uint16_t new_ip)
|
|
{
|
|
cpu_state.pc = new_ip;
|
|
}
|
|
|
|
static void
|
|
startx86(void)
|
|
{
|
|
/* Reset takes 6 cycles before first fetch. */
|
|
do_cycle();
|
|
biu_suspend_fetch();
|
|
do_cycles_i(2);
|
|
biu_queue_flush();
|
|
do_cycles_i(3);
|
|
}
|
|
|
|
static void
|
|
load_cs(uint16_t seg)
|
|
{
|
|
cpu_state.seg_cs.base = seg << 4;
|
|
cpu_state.seg_cs.seg = seg & 0xffff;
|
|
}
|
|
|
|
static void
|
|
load_seg(uint16_t seg, x86seg *s)
|
|
{
|
|
s->base = seg << 4;
|
|
s->seg = seg & 0xffff;
|
|
}
|
|
|
|
static uint8_t
|
|
fetch_i8080_opcode(UNUSED(void* priv), uint16_t addr)
|
|
{
|
|
return readmemb(cs, addr);
|
|
}
|
|
|
|
static uint8_t
|
|
fetch_i8080_data(UNUSED(void* priv), uint16_t addr)
|
|
{
|
|
return readmemb(ds, addr);
|
|
}
|
|
|
|
static void
|
|
put_i8080_data(UNUSED(void* priv), uint16_t addr, uint8_t val)
|
|
{
|
|
writememb(ds, addr, val);
|
|
}
|
|
|
|
static
|
|
uint8_t i8080_port_in(UNUSED(void* priv), uint8_t port)
|
|
{
|
|
cpu_data = port;
|
|
cpu_state.eaaddr = cpu_data;
|
|
cpu_io_vx0(8, 0, cpu_state.eaaddr);
|
|
return AL;
|
|
}
|
|
|
|
static
|
|
void i8080_port_out(UNUSED(void* priv), uint8_t port, uint8_t val)
|
|
{
|
|
cpu_data = DX;
|
|
AL = val;
|
|
do_cycle_i();
|
|
|
|
cpu_state.eaaddr = cpu_data;
|
|
cpu_data = AL;
|
|
cpu_io_vx0(8, 1, port);
|
|
}
|
|
|
|
void
|
|
reset_vx0(int hard)
|
|
{
|
|
halted = 0;
|
|
in_hlt = 0;
|
|
in_0f = 0;
|
|
in_rep = 0;
|
|
in_lock = 0;
|
|
completed = 1;
|
|
repeating = 0;
|
|
clear_lock = 0;
|
|
ovr_seg = NULL;
|
|
|
|
if (hard) {
|
|
opseg[0] = &es;
|
|
opseg[1] = &cs;
|
|
opseg[2] = &ss;
|
|
opseg[3] = &ds;
|
|
_opseg[0] = &cpu_state.seg_es;
|
|
_opseg[1] = &cpu_state.seg_cs;
|
|
_opseg[2] = &cpu_state.seg_ss;
|
|
_opseg[3] = &cpu_state.seg_ds;
|
|
}
|
|
|
|
load_cs(0xFFFF);
|
|
cpu_state.pc = 0;
|
|
|
|
if (is_nec)
|
|
cpu_state.flags |= MD_FLAG;
|
|
rammask = 0xfffff;
|
|
|
|
cpu_alu_op = 0;
|
|
|
|
nx = 0;
|
|
|
|
use_custom_nmi_vector = 0x00;
|
|
custom_nmi_vector = 0x00000000;
|
|
|
|
biu_reset();
|
|
|
|
started = 1;
|
|
modrm_loaded = 0;
|
|
|
|
cpu_md_write_disable = 1;
|
|
i8080_init(&emulated_processor);
|
|
emulated_processor.write_byte = put_i8080_data;
|
|
emulated_processor.read_byte = fetch_i8080_data;
|
|
emulated_processor.read_byte_seg = fetch_i8080_opcode;
|
|
emulated_processor.port_in = i8080_port_in;
|
|
emulated_processor.port_out = i8080_port_out;
|
|
}
|
|
|
|
static uint16_t
|
|
get_accum(int bits)
|
|
{
|
|
return (bits == 16) ? AX : AL;
|
|
}
|
|
|
|
static void
|
|
set_accum(int bits, uint16_t val)
|
|
{
|
|
if (bits == 16)
|
|
AX = val;
|
|
else
|
|
AL = val;
|
|
}
|
|
|
|
static uint16_t
|
|
sign_extend(uint8_t data)
|
|
{
|
|
return data + (data < 0x80 ? 0 : 0xff00);
|
|
}
|
|
|
|
#undef getr8
|
|
#define getr8(r) ((r & 4) ? cpu_state.regs[r & 3].b.h : cpu_state.regs[r & 3].b.l)
|
|
|
|
#undef setr8
|
|
#define setr8(r, v) \
|
|
if (r & 4) \
|
|
cpu_state.regs[r & 3].b.h = v; \
|
|
else \
|
|
cpu_state.regs[r & 3].b.l = v;
|
|
|
|
/* Reads a byte from the effective address. */
|
|
static uint8_t
|
|
geteab(void)
|
|
{
|
|
uint8_t ret;
|
|
|
|
if (cpu_mod == 3)
|
|
ret = (getr8(cpu_rm));
|
|
else
|
|
ret = readmemb(easeg, cpu_state.eaaddr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Reads a word from the effective address. */
|
|
static uint16_t
|
|
geteaw(void)
|
|
{
|
|
uint16_t ret;
|
|
|
|
if (cpu_mod == 3)
|
|
ret = cpu_state.regs[cpu_rm].w;
|
|
else
|
|
ret = readmemw(easeg, cpu_state.eaaddr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Neede for 8087 - memory only. */
|
|
static uint32_t
|
|
geteal(void)
|
|
{
|
|
uint32_t ret;
|
|
|
|
if (cpu_mod == 3) {
|
|
fatal("808x register geteal()\n");
|
|
ret = 0xffffffff;
|
|
} else
|
|
ret = readmeml(easeg, cpu_state.eaaddr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Neede for 8087 - memory only. */
|
|
static uint64_t
|
|
geteaq(void)
|
|
{
|
|
uint32_t ret;
|
|
|
|
if (cpu_mod == 3) {
|
|
fatal("808x register geteaq()\n");
|
|
ret = 0xffffffff;
|
|
} else
|
|
ret = readmemq(easeg, cpu_state.eaaddr);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
read_ea(int memory_only, int bits)
|
|
{
|
|
if (cpu_mod != 3) {
|
|
if (bits == 16)
|
|
cpu_data = readmemw(easeg, cpu_state.eaaddr);
|
|
else
|
|
cpu_data = readmemb(easeg, cpu_state.eaaddr);
|
|
return;
|
|
}
|
|
if (!memory_only) {
|
|
if (bits == 8) {
|
|
cpu_data = getr8(cpu_rm);
|
|
} else
|
|
cpu_data = cpu_state.regs[cpu_rm].w;
|
|
}
|
|
}
|
|
|
|
static void
|
|
read_ea_8to16(void)
|
|
{
|
|
cpu_data = cpu_state.regs[cpu_rm & 3].w;
|
|
}
|
|
|
|
static void
|
|
read_ea2(int bits)
|
|
{
|
|
cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff;
|
|
if (bits == 16)
|
|
cpu_data = readmemw(easeg, cpu_state.eaaddr);
|
|
else
|
|
cpu_data = readmemb(easeg, cpu_state.eaaddr);
|
|
}
|
|
|
|
/* Writes a byte to the effective address. */
|
|
static void
|
|
seteab(uint8_t val)
|
|
{
|
|
if (cpu_mod == 3) {
|
|
setr8(cpu_rm, val);
|
|
} else {
|
|
do_cycle();
|
|
writememb(easeg, cpu_state.eaaddr, val);
|
|
}
|
|
}
|
|
|
|
/* Writes a word to the effective address. */
|
|
static void
|
|
seteaw(uint16_t val)
|
|
{
|
|
if (cpu_mod == 3)
|
|
cpu_state.regs[cpu_rm].w = val;
|
|
else {
|
|
do_cycle();
|
|
writememw(easeg, cpu_state.eaaddr, val);
|
|
}
|
|
}
|
|
|
|
static void
|
|
seteal(uint32_t val)
|
|
{
|
|
if (cpu_mod == 3) {
|
|
fatal("808x register seteal()\n");
|
|
return;
|
|
} else
|
|
writememl(easeg, cpu_state.eaaddr, val);
|
|
}
|
|
|
|
static void
|
|
seteaq(uint64_t val)
|
|
{
|
|
if (cpu_mod == 3) {
|
|
fatal("808x register seteaq()\n");
|
|
return;
|
|
} else
|
|
writememq(easeg, cpu_state.eaaddr, val);
|
|
}
|
|
|
|
/* Leave out the 686 stuff as it's not needed and
|
|
complicates compiling. */
|
|
#define FPU_8087
|
|
#define FPU_NEC
|
|
#define tempc tempc_fpu
|
|
#include "x87_sf.h"
|
|
#include "x87.h"
|
|
#include "x87_ops.h"
|
|
#undef tempc
|
|
#undef FPU_8087
|
|
|
|
static void
|
|
set_cf(int cond)
|
|
{
|
|
cpu_state.flags = (cpu_state.flags & ~C_FLAG) | (cond ? C_FLAG : 0);
|
|
}
|
|
|
|
static void
|
|
set_df(int cond)
|
|
{
|
|
cpu_state.flags = (cpu_state.flags & ~D_FLAG) | (cond ? D_FLAG : 0);
|
|
}
|
|
|
|
static void
|
|
set_of(int of)
|
|
{
|
|
cpu_state.flags = (cpu_state.flags & ~0x800) | (of ? 0x800 : 0);
|
|
}
|
|
|
|
static int
|
|
top_bit(uint16_t w, int bits)
|
|
{
|
|
return (w & (1 << (bits - 1)));
|
|
}
|
|
|
|
static void
|
|
set_of_add(int bits)
|
|
{
|
|
set_of(top_bit((cpu_data ^ cpu_src) & (cpu_data ^ cpu_dest), bits));
|
|
}
|
|
|
|
static void
|
|
set_of_sub(int bits)
|
|
{
|
|
set_of(top_bit((cpu_dest ^ cpu_src) & (cpu_data ^ cpu_dest), bits));
|
|
}
|
|
|
|
static void
|
|
set_af(int af)
|
|
{
|
|
cpu_state.flags = (cpu_state.flags & ~0x10) | (af ? 0x10 : 0);
|
|
}
|
|
|
|
static void
|
|
do_af(void)
|
|
{
|
|
set_af(((cpu_data ^ cpu_src ^ cpu_dest) & 0x10) != 0);
|
|
}
|
|
|
|
static void
|
|
set_sf(int bits)
|
|
{
|
|
cpu_state.flags = (cpu_state.flags & ~0x80) | (top_bit(cpu_data, bits) ? 0x80 : 0);
|
|
}
|
|
|
|
static void
|
|
set_pf(void)
|
|
{
|
|
cpu_state.flags = (cpu_state.flags & ~4) | (!__builtin_parity(cpu_data & 0xFF) << 2);
|
|
}
|
|
|
|
static void
|
|
set_of_rotate(int bits)
|
|
{
|
|
set_of(top_bit(cpu_data ^ cpu_dest, bits));
|
|
}
|
|
|
|
static void
|
|
set_zf_ex(int zf)
|
|
{
|
|
cpu_state.flags = (cpu_state.flags & ~0x40) | (zf ? 0x40 : 0);
|
|
}
|
|
|
|
static void
|
|
set_zf(int bits)
|
|
{
|
|
int size_mask = (1 << bits) - 1;
|
|
|
|
set_zf_ex((cpu_data & size_mask) == 0);
|
|
}
|
|
|
|
static void
|
|
set_pzs(int bits)
|
|
{
|
|
set_pf();
|
|
set_zf(bits);
|
|
set_sf(bits);
|
|
}
|
|
|
|
static void
|
|
set_apzs(int bits)
|
|
{
|
|
set_pzs(bits);
|
|
do_af();
|
|
}
|
|
|
|
static void
|
|
add(int bits)
|
|
{
|
|
int size_mask = (1 << bits) - 1;
|
|
|
|
cpu_data = cpu_dest + cpu_src;
|
|
set_apzs(bits);
|
|
set_of_add(bits);
|
|
|
|
/* Anything - FF with carry on is basically anything + 0x100: value stays
|
|
unchanged but carry goes on. */
|
|
if ((cpu_alu_op == 2) && !(cpu_src & size_mask) && (cpu_state.flags & C_FLAG))
|
|
cpu_state.flags |= C_FLAG;
|
|
else
|
|
set_cf((cpu_src & size_mask) > (cpu_data & size_mask));
|
|
}
|
|
|
|
static void
|
|
sub(int bits)
|
|
{
|
|
int size_mask = (1 << bits) - 1;
|
|
|
|
cpu_data = cpu_dest - cpu_src;
|
|
set_apzs(bits);
|
|
set_of_sub(bits);
|
|
|
|
/* Anything - FF with carry on is basically anything - 0x100: value stays
|
|
unchanged but carry goes on. */
|
|
if ((cpu_alu_op == 3) && !(cpu_src & size_mask) && (cpu_state.flags & C_FLAG))
|
|
cpu_state.flags |= C_FLAG;
|
|
else
|
|
set_cf((cpu_src & size_mask) > (cpu_dest & size_mask));
|
|
}
|
|
|
|
static void
|
|
bitwise(int bits, uint16_t data)
|
|
{
|
|
cpu_data = data;
|
|
cpu_state.flags &= ~(C_FLAG | A_FLAG | V_FLAG);
|
|
set_pzs(bits);
|
|
}
|
|
|
|
static void
|
|
test(int bits, uint16_t dest, uint16_t src)
|
|
{
|
|
cpu_dest = dest;
|
|
cpu_src = src;
|
|
bitwise(bits, (cpu_dest & cpu_src));
|
|
}
|
|
|
|
static void
|
|
alu_op(int bits)
|
|
{
|
|
switch (cpu_alu_op) {
|
|
case 1:
|
|
bitwise(bits, (cpu_dest | cpu_src));
|
|
break;
|
|
case 2:
|
|
if (cpu_state.flags & C_FLAG)
|
|
cpu_src++;
|
|
fallthrough;
|
|
case 0:
|
|
add(bits);
|
|
break;
|
|
case 3:
|
|
if (cpu_state.flags & C_FLAG)
|
|
cpu_src++;
|
|
fallthrough;
|
|
case 5:
|
|
case 7:
|
|
sub(bits);
|
|
break;
|
|
case 4:
|
|
test(bits, cpu_dest, cpu_src);
|
|
break;
|
|
case 6:
|
|
bitwise(bits, (cpu_dest ^ cpu_src));
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
mul(uint16_t a, uint16_t b)
|
|
{
|
|
int negate = 0;
|
|
int bit_count = 8;
|
|
int carry;
|
|
uint16_t high_bit = 0x80;
|
|
uint16_t size_mask;
|
|
uint16_t c;
|
|
uint16_t r;
|
|
|
|
size_mask = (1 << bit_count) - 1;
|
|
|
|
if (opcode != 0xd5) {
|
|
if (opcode & 1) {
|
|
bit_count = 16;
|
|
high_bit = 0x8000;
|
|
} else
|
|
do_cycles(8);
|
|
|
|
size_mask = (1 << bit_count) - 1;
|
|
|
|
if ((rmdat & 0x38) == 0x28) {
|
|
if (!top_bit(a, bit_count)) {
|
|
if (top_bit(b, bit_count)) {
|
|
do_cycle();
|
|
if ((b & size_mask) != ((opcode & 1) ? 0x8000 : 0x80))
|
|
do_cycle();
|
|
b = ~b + 1;
|
|
negate = 1;
|
|
}
|
|
} else {
|
|
do_cycle();
|
|
a = ~a + 1;
|
|
negate = 1;
|
|
if (top_bit(b, bit_count)) {
|
|
b = ~b + 1;
|
|
negate = 0;
|
|
} else
|
|
do_cycles(4);
|
|
}
|
|
do_cycles(10);
|
|
}
|
|
do_cycles(3);
|
|
}
|
|
|
|
c = 0;
|
|
a &= size_mask;
|
|
carry = (a & 1) != 0;
|
|
a >>= 1;
|
|
for (int i = 0; i < bit_count; ++i) {
|
|
do_cycles(7);
|
|
if (carry) {
|
|
cpu_src = c;
|
|
cpu_dest = b;
|
|
add(bit_count);
|
|
c = cpu_data & size_mask;
|
|
do_cycles(1);
|
|
carry = !!(cpu_state.flags & C_FLAG);
|
|
}
|
|
r = (c >> 1) + (carry ? high_bit : 0);
|
|
carry = (c & 1) != 0;
|
|
c = r;
|
|
r = (a >> 1) + (carry ? high_bit : 0);
|
|
carry = (a & 1) != 0;
|
|
a = r;
|
|
}
|
|
if (negate) {
|
|
c = ~c;
|
|
a = (~a + 1) & size_mask;
|
|
if (a == 0)
|
|
++c;
|
|
do_cycles(9);
|
|
}
|
|
cpu_data = a;
|
|
cpu_dest = c;
|
|
|
|
set_sf(bit_count);
|
|
set_pf();
|
|
set_af(0);
|
|
}
|
|
|
|
static void
|
|
set_co_mul(UNUSED(int bits), int carry)
|
|
{
|
|
set_cf(carry);
|
|
set_of(carry);
|
|
set_zf_ex(!carry);
|
|
if (!carry)
|
|
do_cycle();
|
|
}
|
|
|
|
/* Pushes a word to the stack. */
|
|
static void
|
|
push(uint16_t *val)
|
|
{
|
|
if ((is186 && !is_nec) && (SP == 1)) {
|
|
writememw(ss - 1, 0, *val);
|
|
SP = cpu_state.eaaddr = 0xFFFF;
|
|
return;
|
|
}
|
|
SP -= 2;
|
|
cpu_state.eaaddr = (SP & 0xffff);
|
|
writememw(ss, cpu_state.eaaddr, *val);
|
|
}
|
|
|
|
/* Pops a word from the stack. */
|
|
static uint16_t
|
|
pop(void)
|
|
{
|
|
cpu_state.eaaddr = (SP & 0xffff);
|
|
SP += 2;
|
|
return readmemw(ss, cpu_state.eaaddr);
|
|
}
|
|
|
|
static void
|
|
nearcall(uint16_t new_ip)
|
|
{
|
|
uint16_t ret_ip = cpu_state.pc & 0xffff;
|
|
|
|
do_cycle_i();
|
|
set_ip(new_ip);
|
|
biu_queue_flush();
|
|
do_cycles_i(3);
|
|
push(&ret_ip);
|
|
}
|
|
|
|
static void
|
|
farcall2(uint16_t new_cs, uint16_t new_ip)
|
|
{
|
|
do_cycles_i(3);
|
|
push(&CS);
|
|
load_cs(new_cs);
|
|
do_cycles_i(2);
|
|
nearcall(new_ip);
|
|
}
|
|
|
|
/* The INTR microcode routine. */
|
|
static void
|
|
intr_routine(uint16_t intr, int skip_first)
|
|
{
|
|
uint16_t vector = intr * 4;
|
|
uint16_t tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7);
|
|
uint16_t new_cs;
|
|
uint16_t new_ip;
|
|
|
|
if (!(cpu_state.flags & MD_FLAG) && is_nec) {
|
|
sync_from_i8080();
|
|
x808x_log("CALLN/INT#/NMI#\n");
|
|
}
|
|
|
|
if (!skip_first)
|
|
do_cycle_i();
|
|
do_cycles_i(2);
|
|
|
|
cpu_state.eaaddr = vector & 0xffff;
|
|
new_ip = readmemw(0, cpu_state.eaaddr);
|
|
do_cycle_i();
|
|
cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff;
|
|
new_cs = readmemw(0, cpu_state.eaaddr);
|
|
|
|
biu_suspend_fetch();
|
|
do_cycles_i(2);
|
|
push(&tempf);
|
|
cpu_state.flags &= ~(I_FLAG | T_FLAG);
|
|
if (is_nec)
|
|
cpu_state.flags |= MD_FLAG;
|
|
do_cycle_i();
|
|
|
|
farcall2(new_cs, new_ip);
|
|
}
|
|
|
|
/* Was div(), renamed to avoid conflicts with stdlib div(). */
|
|
static int
|
|
x86_div(uint16_t l, uint16_t h)
|
|
{
|
|
int bit_count = 8;
|
|
int negative = 0;
|
|
int dividend_negative = 0;
|
|
int size_mask;
|
|
int carry;
|
|
uint16_t r;
|
|
|
|
if (opcode & 1) {
|
|
l = AX;
|
|
h = DX;
|
|
bit_count = 16;
|
|
}
|
|
|
|
size_mask = (1 << bit_count) - 1;
|
|
|
|
if (opcode != 0xd4) {
|
|
if ((rmdat & 0x38) == 0x38) {
|
|
if (top_bit(h, bit_count)) {
|
|
h = ~h;
|
|
l = (~l + 1) & size_mask;
|
|
if (l == 0)
|
|
++h;
|
|
h &= size_mask;
|
|
negative = 1;
|
|
dividend_negative = 1;
|
|
do_cycles(4);
|
|
}
|
|
if (top_bit(cpu_src, bit_count)) {
|
|
cpu_src = ~cpu_src + 1;
|
|
negative = !negative;
|
|
} else
|
|
do_cycle();
|
|
do_cycles(9);
|
|
}
|
|
do_cycles(3);
|
|
}
|
|
do_cycles(8);
|
|
cpu_src &= size_mask;
|
|
if (h >= cpu_src) {
|
|
if (opcode != 0xd4)
|
|
do_cycle();
|
|
intr_routine(0, 0);
|
|
return 0;
|
|
}
|
|
if (opcode != 0xd4)
|
|
do_cycle();
|
|
do_cycles(2);
|
|
carry = 1;
|
|
for (int b = 0; b < bit_count; ++b) {
|
|
r = (l << 1) + (carry ? 1 : 0);
|
|
carry = top_bit(l, bit_count);
|
|
l = r;
|
|
r = (h << 1) + (carry ? 1 : 0);
|
|
carry = top_bit(h, bit_count);
|
|
h = r;
|
|
do_cycles(8);
|
|
if (carry) {
|
|
carry = 0;
|
|
h -= cpu_src;
|
|
if (b == bit_count - 1)
|
|
do_cycles(2);
|
|
} else {
|
|
carry = cpu_src > h;
|
|
if (!carry) {
|
|
h -= cpu_src;
|
|
do_cycle();
|
|
if (b == bit_count - 1)
|
|
do_cycles(2);
|
|
}
|
|
}
|
|
}
|
|
l = ~((l << 1) + (carry ? 1 : 0));
|
|
if (opcode != 0xd4 && (rmdat & 0x38) == 0x38) {
|
|
do_cycles(4);
|
|
if (top_bit(l, bit_count)) {
|
|
if (cpu_mod == 3)
|
|
do_cycle();
|
|
intr_routine(0, 0);
|
|
return 0;
|
|
}
|
|
do_cycles(7);
|
|
if (negative)
|
|
l = ~l + 1;
|
|
if (dividend_negative)
|
|
h = ~h + 1;
|
|
}
|
|
if (opcode == 0xd4) {
|
|
AL = h & 0xff;
|
|
AH = l & 0xff;
|
|
} else {
|
|
AH = h & 0xff;
|
|
AL = l & 0xff;
|
|
if (opcode & 1) {
|
|
DX = h;
|
|
AX = l;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static uint16_t
|
|
string_increment(int bits)
|
|
{
|
|
int d = bits >> 3;
|
|
if (cpu_state.flags & D_FLAG)
|
|
cpu_state.eaaddr -= d;
|
|
else
|
|
cpu_state.eaaddr += d;
|
|
cpu_state.eaaddr &= 0xffff;
|
|
return cpu_state.eaaddr;
|
|
}
|
|
|
|
static void
|
|
lods(int bits)
|
|
{
|
|
cpu_state.eaaddr = SI;
|
|
if (bits == 16)
|
|
cpu_data = readmemw((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr);
|
|
else
|
|
cpu_data = readmemb((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr);
|
|
SI = string_increment(bits);
|
|
}
|
|
|
|
static void
|
|
lods_di(int bits)
|
|
{
|
|
cpu_state.eaaddr = DI;
|
|
if (bits == 16)
|
|
cpu_data = readmemw(es, cpu_state.eaaddr);
|
|
else
|
|
cpu_data = readmemb(es, cpu_state.eaaddr);
|
|
DI = string_increment(bits);
|
|
}
|
|
|
|
static void
|
|
stos(int bits)
|
|
{
|
|
cpu_state.eaaddr = DI;
|
|
if (bits == 16)
|
|
writememw(es, cpu_state.eaaddr, cpu_data);
|
|
else
|
|
writememb(es, cpu_state.eaaddr, (uint8_t) (cpu_data & 0xff));
|
|
DI = string_increment(bits);
|
|
}
|
|
|
|
static uint16_t
|
|
get_ea(void)
|
|
{
|
|
if (opcode & 1)
|
|
return geteaw();
|
|
else
|
|
return (uint16_t) geteab();
|
|
}
|
|
|
|
static uint16_t
|
|
get_reg(uint8_t reg)
|
|
{
|
|
if (opcode & 1)
|
|
return cpu_state.regs[reg].w;
|
|
else
|
|
return (uint16_t) getr8(reg);
|
|
}
|
|
|
|
static void
|
|
set_ea(uint16_t val)
|
|
{
|
|
if (opcode & 1)
|
|
seteaw(val);
|
|
else
|
|
seteab((uint8_t) (val & 0xff));
|
|
}
|
|
|
|
static void
|
|
set_reg(uint8_t reg, uint16_t val)
|
|
{
|
|
if (opcode & 1)
|
|
cpu_state.regs[reg].w = val;
|
|
else
|
|
setr8(reg, (uint8_t) (val & 0xff));
|
|
}
|
|
|
|
static void
|
|
cpu_data_opff_rm(void)
|
|
{
|
|
if (!(opcode & 1)) {
|
|
if (cpu_mod != 3)
|
|
cpu_data |= 0xff00;
|
|
else
|
|
cpu_data = cpu_state.regs[cpu_rm].w;
|
|
}
|
|
}
|
|
|
|
static void
|
|
farcall(uint16_t new_cs, uint16_t new_ip, int jump)
|
|
{
|
|
if (jump)
|
|
do_cycle_i();
|
|
biu_suspend_fetch();
|
|
do_cycles_i(2);
|
|
push(&CS);
|
|
load_cs(new_cs);
|
|
do_cycles_i(2);
|
|
nearcall(new_ip);
|
|
}
|
|
|
|
/* Calls an interrupt. */
|
|
static void
|
|
sw_int(uint16_t intr)
|
|
{
|
|
uint16_t vector = intr * 4;
|
|
uint16_t tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7);
|
|
uint16_t new_cs;
|
|
uint16_t new_ip;
|
|
uint16_t old_ip;
|
|
|
|
if (!(cpu_state.flags & MD_FLAG) && is_nec) {
|
|
sync_from_i8080();
|
|
x808x_log("CALLN/INT#/NMI#\n");
|
|
}
|
|
|
|
do_cycles_i(3);
|
|
cpu_state.eaaddr = vector & 0xffff;
|
|
new_ip = readmemw(0, cpu_state.eaaddr);
|
|
do_cycle_i();
|
|
cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff;
|
|
new_cs = readmemw(0, cpu_state.eaaddr);
|
|
|
|
biu_suspend_fetch();
|
|
do_cycles_i(2);
|
|
push(&tempf);
|
|
cpu_state.flags &= ~(I_FLAG | T_FLAG);
|
|
if (is_nec)
|
|
cpu_state.flags |= MD_FLAG;
|
|
|
|
/* FARCALL2 */
|
|
do_cycles_i(4);
|
|
push(&CS);
|
|
load_cs(new_cs);
|
|
do_cycle_i();
|
|
|
|
/* NEARCALL */
|
|
old_ip = cpu_state.pc & 0xffff;
|
|
do_cycles_i(2);
|
|
set_ip(new_ip);
|
|
biu_queue_flush();
|
|
do_cycles_i(3);
|
|
push(&old_ip);
|
|
}
|
|
|
|
static void
|
|
int3(void)
|
|
{
|
|
do_cycles_i(4);
|
|
intr_routine(3, 0);
|
|
}
|
|
|
|
/* Ditto, but for breaking into emulation mode. */
|
|
static void
|
|
interrupt_brkem(uint16_t addr)
|
|
{
|
|
uint16_t tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7);
|
|
uint16_t new_cs;
|
|
uint16_t new_ip;
|
|
uint16_t old_ip;
|
|
|
|
do_cycles_i(3);
|
|
cpu_state.eaaddr = addr << 2;
|
|
new_ip = readmemw(0, cpu_state.eaaddr);
|
|
do_cycle_i();
|
|
cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff;
|
|
new_cs = readmemw(0, cpu_state.eaaddr);
|
|
|
|
biu_suspend_fetch();
|
|
do_cycles_i(2);
|
|
push(&tempf);
|
|
cpu_state.flags &= ~(MD_FLAG);
|
|
cpu_md_write_disable = 0;
|
|
|
|
/* FARCALL2 */
|
|
do_cycles_i(4);
|
|
push(&CS);
|
|
load_cs(new_cs);
|
|
do_cycle_i();
|
|
|
|
/* NEARCALL */
|
|
old_ip = cpu_state.pc & 0xffff;
|
|
do_cycles_i(2);
|
|
set_ip(new_ip);
|
|
biu_queue_flush();
|
|
do_cycles_i(3);
|
|
push(&old_ip);
|
|
|
|
sync_to_i8080();
|
|
x808x_log("BRKEM mode\n");
|
|
}
|
|
|
|
void
|
|
retem_i8080(void)
|
|
{
|
|
sync_from_i8080();
|
|
|
|
do_cycle_i();
|
|
farret(1);
|
|
/* pop_flags() */
|
|
cpu_state.flags = pop();
|
|
do_cycle_i();
|
|
|
|
noint = 1;
|
|
nmi_enable = 1;
|
|
|
|
emulated_processor.iff = !!(cpu_state.flags & I_FLAG);
|
|
|
|
cpu_md_write_disable = 1;
|
|
|
|
retem = 1;
|
|
|
|
x808x_log("RETEM mode\n");
|
|
}
|
|
|
|
void
|
|
interrupt_808x(uint16_t addr)
|
|
{
|
|
biu_suspend_fetch();
|
|
do_cycles_i(2);
|
|
|
|
intr_routine(addr, 0);
|
|
}
|
|
|
|
static void
|
|
custom_nmi(void)
|
|
{
|
|
uint16_t tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7);
|
|
uint16_t new_cs;
|
|
uint16_t new_ip;
|
|
|
|
if (!(cpu_state.flags & MD_FLAG) && is_nec) {
|
|
sync_from_i8080();
|
|
x808x_log("CALLN/INT#/NMI#\n");
|
|
}
|
|
|
|
do_cycle_i();
|
|
do_cycles_i(2);
|
|
|
|
cpu_state.eaaddr = 0x0002;
|
|
(void) readmemw(0, cpu_state.eaaddr);
|
|
new_ip = custom_nmi_vector & 0xffff;
|
|
do_cycle_i();
|
|
cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff;
|
|
(void) readmemw(0, cpu_state.eaaddr);
|
|
new_cs = custom_nmi_vector >> 16;
|
|
|
|
biu_suspend_fetch();
|
|
do_cycles_i(2);
|
|
push(&tempf);
|
|
cpu_state.flags &= ~(I_FLAG | T_FLAG);
|
|
if (is_nec)
|
|
cpu_state.flags |= MD_FLAG;
|
|
do_cycle_i();
|
|
|
|
farcall2(new_cs, new_ip);
|
|
}
|
|
|
|
static int
|
|
irq_pending(void)
|
|
{
|
|
uint8_t temp;
|
|
|
|
temp = (nmi && nmi_enable && nmi_mask) || ((cpu_state.flags & T_FLAG) && !noint) ||
|
|
((in_hlt || (cpu_state.flags & I_FLAG)) && pic.int_pending && !noint);
|
|
|
|
return temp;
|
|
}
|
|
|
|
static int
|
|
bus_pic_ack(void)
|
|
{
|
|
int old_in_lock = in_lock;
|
|
|
|
in_lock = 1;
|
|
bus_request_type = BUS_PIC;
|
|
biu_begin_eu();
|
|
biu_wait_for_read_finish();
|
|
in_lock = old_in_lock;
|
|
return pic_data;
|
|
}
|
|
|
|
static void
|
|
hw_int(uint16_t vector)
|
|
{
|
|
biu_suspend_fetch();
|
|
do_cycles_i(2);
|
|
|
|
intr_routine(vector, 0);
|
|
}
|
|
|
|
static void
|
|
int1(void)
|
|
{
|
|
do_cycles_i(2);
|
|
intr_routine(1, 1);
|
|
}
|
|
|
|
static void
|
|
int2(void)
|
|
{
|
|
do_cycles_i(2);
|
|
intr_routine(2, 1);
|
|
}
|
|
|
|
static void
|
|
check_interrupts(void)
|
|
{
|
|
int temp;
|
|
|
|
if (irq_pending()) {
|
|
if ((cpu_state.flags & T_FLAG) && !noint) {
|
|
int1();
|
|
return;
|
|
}
|
|
if (nmi && nmi_enable && nmi_mask) {
|
|
nmi_enable = 0;
|
|
if (use_custom_nmi_vector) {
|
|
do_cycles(2);
|
|
custom_nmi();
|
|
} else
|
|
int2();
|
|
return;
|
|
}
|
|
if ((in_hlt || (cpu_state.flags & I_FLAG)) && pic.int_pending && !noint) {
|
|
repeating = 0;
|
|
completed = 1;
|
|
ovr_seg = NULL;
|
|
do_cycles(4);
|
|
/* ACK to PIC */
|
|
biu_begin_eu();
|
|
temp = bus_pic_ack();
|
|
do_cycle();
|
|
/* ACK to PIC */
|
|
temp = bus_pic_ack();
|
|
in_lock = 0;
|
|
clear_lock = 0;
|
|
/* Here is where temp should be filled, but we cheat. */
|
|
opcode = 0x00;
|
|
hw_int(temp);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* The FARRET microcode routine. */
|
|
static void
|
|
farret(int far)
|
|
{
|
|
uint8_t far2 = !!(opcode & 0x08);
|
|
|
|
do_cycle_i();
|
|
set_ip(pop());
|
|
biu_suspend_fetch();
|
|
do_cycles_i(2);
|
|
|
|
if ((!!far) != far2)
|
|
fatal("Far call distance mismatch (%i = %i)\n", !!far, far2);
|
|
|
|
if (far) {
|
|
do_cycle_i();
|
|
load_cs(pop());
|
|
|
|
biu_queue_flush();
|
|
do_cycles_i(2);
|
|
} else {
|
|
biu_queue_flush();
|
|
do_cycles_i(2);
|
|
}
|
|
|
|
do_cycles_i(2);
|
|
}
|
|
|
|
static void
|
|
iret_routine(void)
|
|
{
|
|
do_cycle_i();
|
|
farret(1);
|
|
/* pop_flags() */
|
|
if (is_nec && cpu_md_write_disable)
|
|
cpu_state.flags = pop() | 0x8002;
|
|
else
|
|
cpu_state.flags = pop() | 0x0002;
|
|
do_cycle_i();
|
|
noint = 1;
|
|
nmi_enable = 1;
|
|
}
|
|
|
|
static void
|
|
rep_end(void)
|
|
{
|
|
repeating = 0;
|
|
in_rep = 0;
|
|
completed = 1;
|
|
}
|
|
|
|
static int
|
|
rep_start(void)
|
|
{
|
|
if (!repeating) {
|
|
if (in_rep != 0) {
|
|
if (CX == 0) {
|
|
do_cycles_i(is_nec ? 1 : 4);
|
|
rep_end();
|
|
return 0;
|
|
} else
|
|
do_cycles_i(is_nec ? 1 : 7);
|
|
}
|
|
}
|
|
|
|
completed = 1;
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
rep_interrupt(void)
|
|
{
|
|
biu_suspend_fetch();
|
|
do_cycles_i(4);
|
|
biu_queue_flush();
|
|
|
|
if (is_nec && (ovr_seg != NULL))
|
|
set_ip((cpu_state.pc - 3) & 0xffff);
|
|
else
|
|
set_ip((cpu_state.pc - 2) & 0xffff);
|
|
|
|
rep_end();
|
|
}
|
|
|
|
static void
|
|
sign_extend_al(void)
|
|
{
|
|
if ((AL & 0x80) != 0)
|
|
AH = 0xff;
|
|
else
|
|
AH = 0x00;
|
|
}
|
|
|
|
static void
|
|
sign_extend_ax(void)
|
|
{
|
|
do_cycles(3);
|
|
if ((AX & 0x8000) == 0)
|
|
DX = 0x0000;
|
|
else {
|
|
do_cycle();
|
|
DX = 0xffff;
|
|
}
|
|
}
|
|
|
|
static void
|
|
reljmp(uint16_t new_ip, int jump)
|
|
{
|
|
if (!is_nec && jump)
|
|
do_cycle_i();
|
|
|
|
biu_suspend_fetch();
|
|
if (!is_nec)
|
|
do_cycles_i(3);
|
|
set_ip(new_ip);
|
|
biu_queue_flush();
|
|
do_cycle_i();
|
|
}
|
|
|
|
static void
|
|
daa(void)
|
|
{
|
|
uint16_t old_cf = cpu_state.flags & C_FLAG;
|
|
uint16_t old_af = cpu_state.flags & A_FLAG;
|
|
uint8_t old_al = AL;
|
|
uint8_t al_check;
|
|
|
|
cpu_state.flags &= ~C_FLAG;
|
|
|
|
al_check = (old_af ? 0x9f : 0x99);
|
|
|
|
cpu_state.flags &= ~V_FLAG;
|
|
if (old_cf) {
|
|
if ((AL >= 0x1a) && (AL <= 0x7f))
|
|
cpu_state.flags |= V_FLAG;
|
|
} else if ((AL >= 0x7a) && (AL <= 0x7f))
|
|
cpu_state.flags |= V_FLAG;
|
|
|
|
if (((AL & 0x0f) > 9) || (cpu_state.flags & A_FLAG)) {
|
|
AL += 6;
|
|
cpu_state.flags |= A_FLAG;
|
|
} else
|
|
cpu_state.flags &= ~A_FLAG;
|
|
|
|
if ((old_al > al_check) || old_cf) {
|
|
AL += 0x60;
|
|
cpu_state.flags |= C_FLAG;
|
|
} else
|
|
cpu_state.flags &= ~C_FLAG;
|
|
|
|
set_pzs(8);
|
|
}
|
|
|
|
static void
|
|
das(void)
|
|
{
|
|
uint8_t old_al = AL;
|
|
uint16_t old_af = cpu_state.flags & A_FLAG;
|
|
uint16_t old_cf = cpu_state.flags & C_FLAG;
|
|
uint8_t al_check = (old_af ? 0x9f : 0x99);
|
|
|
|
cpu_state.flags &= ~V_FLAG;
|
|
|
|
if (!old_af && !old_cf) {
|
|
if ((AL >= 0x9a) && (AL <= 0xdf))
|
|
cpu_state.flags |= V_FLAG;
|
|
} else if (old_af && !old_cf) {
|
|
if (((AL >= 0x80) && (AL <= 0x85)) || ((AL >= 0xa0) && (AL <= 0xe5)))
|
|
cpu_state.flags |= V_FLAG;
|
|
} else if (!old_af && old_cf) {
|
|
if ((AL >= 0x80) && (AL <= 0xdf))
|
|
cpu_state.flags |= V_FLAG;
|
|
} else if (old_af && old_cf) {
|
|
if ((AL >= 0x80) && (AL <= 0xe5))
|
|
cpu_state.flags |= V_FLAG;
|
|
}
|
|
|
|
cpu_state.flags &= ~C_FLAG;
|
|
if (((AL & 0x0f) > 9) || (cpu_state.flags & A_FLAG)) {
|
|
AL -= 6;
|
|
cpu_state.flags |= A_FLAG;
|
|
} else
|
|
cpu_state.flags &= ~A_FLAG;
|
|
|
|
if ((old_al > al_check) || old_cf) {
|
|
AL -= 0x60;
|
|
cpu_state.flags |= C_FLAG;
|
|
} else
|
|
cpu_state.flags &= ~C_FLAG;
|
|
|
|
set_pzs(8);
|
|
}
|
|
|
|
static void
|
|
aaa(void)
|
|
{
|
|
uint8_t old_al = AL;
|
|
uint8_t new_al;
|
|
|
|
if (((AL & 0x0f) > 9) || (cpu_state.flags & A_FLAG)) {
|
|
AH += 1;
|
|
new_al = AL + 6;
|
|
AL = new_al & 0x0f;
|
|
cpu_state.flags |= A_FLAG;
|
|
cpu_state.flags |= C_FLAG;
|
|
} else {
|
|
new_al = AL;
|
|
AL &= 0x0f;
|
|
cpu_state.flags &= ~A_FLAG;
|
|
cpu_state.flags &= ~C_FLAG;
|
|
do_cycle_i();
|
|
}
|
|
|
|
cpu_state.flags &= ~(V_FLAG | Z_FLAG | N_FLAG);
|
|
if (new_al == 0x00)
|
|
cpu_state.flags |= Z_FLAG;
|
|
if ((old_al >= 0x7a) && (old_al <= 0x7f))
|
|
cpu_state.flags |= V_FLAG;
|
|
if ((old_al >= 0x7a) && (old_al <= 0xf9))
|
|
cpu_state.flags |= N_FLAG;
|
|
|
|
cpu_data = new_al;
|
|
set_pf();
|
|
}
|
|
|
|
static void
|
|
aas(void)
|
|
{
|
|
uint8_t old_al = AL;
|
|
uint16_t old_af = cpu_state.flags & A_FLAG;
|
|
uint8_t new_al;
|
|
|
|
do_cycles_i(6);
|
|
|
|
if (((AL & 0x0f) > 9) || old_af) {
|
|
new_al = AL - 6;
|
|
AH++;
|
|
AL = new_al & 0x0f;
|
|
cpu_state.flags |= (A_FLAG | C_FLAG);
|
|
} else {
|
|
new_al = AL;
|
|
AL &= 0x0f;
|
|
cpu_state.flags &= ~(C_FLAG | A_FLAG);
|
|
do_cycle_i();
|
|
}
|
|
|
|
cpu_state.flags &= ~(V_FLAG | Z_FLAG | N_FLAG);
|
|
if (new_al == 0x00)
|
|
cpu_state.flags |= Z_FLAG;
|
|
if (old_af && (old_al >= 0x80) && (old_al <= 0x85))
|
|
cpu_state.flags |= V_FLAG;
|
|
if (!old_af && (old_al >= 0x80))
|
|
cpu_state.flags |= N_FLAG;
|
|
if (old_af && ((old_al <= 0x05) || (old_al >= 0x86)))
|
|
cpu_state.flags |= N_FLAG;
|
|
|
|
cpu_data = new_al;
|
|
set_pf();
|
|
}
|
|
|
|
static void
|
|
finalize(void)
|
|
{
|
|
in_0f = 0;
|
|
repeating = 0;
|
|
ovr_seg = NULL;
|
|
in_rep = 0;
|
|
rep_c_flag = 0;
|
|
if (in_lock)
|
|
clear_lock = 1;
|
|
cpu_alu_op = 0;
|
|
|
|
if (pfq_pos == 0) {
|
|
do {
|
|
if (nx)
|
|
nx = 0;
|
|
do_cycle();
|
|
} while (pfq_pos == 0);
|
|
biu_preload_byte = biu_pfq_read();
|
|
biu_queue_preload = 1;
|
|
do_cycle();
|
|
} else {
|
|
biu_queue_preload = 1;
|
|
biu_preload_byte = biu_pfq_read();
|
|
|
|
biu_resume_on_queue_read();
|
|
|
|
do_cycle();
|
|
}
|
|
|
|
if (irq_pending())
|
|
cpu_state.pc--;
|
|
}
|
|
|
|
/* Fetches the effective address from the prefetch queue according to MOD and R/M. */
|
|
static void
|
|
do_mod_rm(void)
|
|
{
|
|
rmdat = biu_pfq_fetchb();
|
|
cpu_reg = (rmdat >> 3) & 7;
|
|
cpu_mod = (rmdat >> 6) & 3;
|
|
cpu_rm = rmdat & 7;
|
|
|
|
if (cpu_mod != 3) {
|
|
do_cycle();
|
|
if (is_nec)
|
|
do_cycle();
|
|
else if (modrm_cycs_pre[rmdat & 0xc7])
|
|
do_cycles(modrm_cycs_pre[rmdat & 0xc7]);
|
|
|
|
if ((rmdat & 0xc7) == 0x06) {
|
|
cpu_state.eaaddr = biu_pfq_fetchw();
|
|
easeg = ovr_seg ? *ovr_seg : ds;
|
|
} else {
|
|
cpu_state.eaaddr = (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]);
|
|
easeg = ovr_seg ? *ovr_seg : *mod1seg[cpu_rm];
|
|
switch (rmdat & 0xc0) {
|
|
default:
|
|
break;
|
|
case 0x40:
|
|
cpu_state.eaaddr += sign_extend(biu_pfq_fetchb());
|
|
break;
|
|
case 0x80:
|
|
cpu_state.eaaddr += biu_pfq_fetchw();
|
|
break;
|
|
}
|
|
cpu_state.eaaddr &= 0xffff;
|
|
}
|
|
|
|
if (!is_nec && modrm_cycs_post[rmdat & 0xc7])
|
|
do_cycles(modrm_cycs_post[rmdat & 0xc7]);
|
|
}
|
|
}
|
|
|
|
static void
|
|
decode(void)
|
|
{
|
|
uint8_t op_f;
|
|
uint8_t prefix = 0;
|
|
|
|
if (halted)
|
|
opcode = 0xf4;
|
|
else
|
|
opcode = biu_pfq_fetchb_common();
|
|
|
|
modrm_loaded = 0;
|
|
|
|
while (1) {
|
|
prefix = 0;
|
|
|
|
switch (opcode) {
|
|
case 0x0f: /* NEC/186 */
|
|
if (is_nec) {
|
|
in_0f = 1;
|
|
prefix = 1;
|
|
}
|
|
break;
|
|
case 0x26: /* ES: */
|
|
case 0x2e: /* CS: */
|
|
case 0x36: /* SS: */
|
|
case 0x3e: /* DS: */
|
|
ovr_seg = opseg[(opcode >> 3) & 0x03];
|
|
prefix = 1;
|
|
break;
|
|
case 0x64: /* REPNC */
|
|
case 0x65: /* REPC */
|
|
if (is_nec) {
|
|
in_rep = (opcode == 0x64 ? 1 : 2);
|
|
rep_c_flag = 1;
|
|
prefix = 1;
|
|
}
|
|
break;
|
|
case 0xf0:
|
|
case 0xf1: /* LOCK - F1 is alias */
|
|
in_lock = 1;
|
|
prefix = 1;
|
|
break;
|
|
case 0xf2: /* REPNE */
|
|
case 0xf3: /* REPE */
|
|
in_rep = (opcode == 0xf2 ? 1 : 2);
|
|
rep_c_flag = 0;
|
|
prefix = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (prefix == 0)
|
|
break;
|
|
|
|
do_cycle();
|
|
|
|
opcode = biu_pfq_fetchb_common();
|
|
}
|
|
|
|
if (is_nec) {
|
|
if (in_0f)
|
|
op_f = (uint8_t) opf_0f[opcode];
|
|
else
|
|
op_f = (uint8_t) opf_nec[opcode];
|
|
} else
|
|
op_f = (uint8_t) opf[opcode];
|
|
|
|
if (op_f & OP_GRP) {
|
|
do_mod_rm();
|
|
modrm_loaded = 1;
|
|
|
|
op_f |= (OP_MRM | OP_EA);
|
|
|
|
if (opcode >= 0xf0) {
|
|
op_f |= OP_DELAY;
|
|
group_delay = 1;
|
|
}
|
|
}
|
|
|
|
if (!modrm_loaded && (op_f & OP_MRM)) {
|
|
do_mod_rm();
|
|
modrm_loaded = 1;
|
|
}
|
|
|
|
if (modrm_loaded && !(op_f & OP_EA)) {
|
|
if (is_nec)
|
|
do_cycle();
|
|
else {
|
|
if (opcode == 0x8f) {
|
|
if (cpu_mod == 3)
|
|
do_cycles_i(2);
|
|
} else
|
|
do_cycles_i(2);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
string_op(int bits)
|
|
{
|
|
uint16_t tmpa;
|
|
uint16_t old_ax;
|
|
|
|
if ((opcode & 0xf0) == 0x60) switch (opcode & 0x0e) {
|
|
case 0x0c:
|
|
old_ax = AX;
|
|
cpu_data = DX;
|
|
cpu_state.eaaddr = cpu_data;
|
|
cpu_io_vx0(bits, 0, cpu_state.eaaddr);
|
|
cpu_data = AX;
|
|
stos(bits);
|
|
AX = old_ax;
|
|
break;
|
|
case 0x0e:
|
|
old_ax = AX;
|
|
lods(bits);
|
|
set_accum(bits, cpu_data);
|
|
cpu_data = DX;
|
|
do_cycle_i();
|
|
/* biu_io_write_u16() */
|
|
cpu_state.eaaddr = cpu_data;
|
|
cpu_io_vx0(bits, 1, cpu_state.eaaddr);
|
|
AX = old_ax;
|
|
break;
|
|
} else switch (opcode & 0x0e) {
|
|
case 0x04:
|
|
lods(bits);
|
|
do_cycle_i();
|
|
stos(bits);
|
|
break;
|
|
case 0x06:
|
|
do_cycle_i();
|
|
if (is_nec) {
|
|
if (in_rep) {
|
|
lods_di(bits);
|
|
tmpa = cpu_data;
|
|
lods(bits);
|
|
} else {
|
|
lods(bits);
|
|
tmpa = cpu_data;
|
|
lods_di(bits);
|
|
}
|
|
} else {
|
|
lods(bits);
|
|
tmpa = cpu_data;
|
|
do_cycles_i(2);
|
|
lods_di(bits);
|
|
do_cycles_i(3);
|
|
}
|
|
|
|
cpu_src = cpu_data;
|
|
cpu_dest = tmpa;
|
|
sub(bits);
|
|
break;
|
|
case 0x0e:
|
|
tmpa = AX;
|
|
do_cycles_i(2);
|
|
lods_di(bits);
|
|
do_cycles_i(3);
|
|
|
|
cpu_src = cpu_data;
|
|
cpu_dest = tmpa;
|
|
sub(bits);
|
|
break;
|
|
case 0x0a:
|
|
cpu_data = AX;
|
|
stos(bits);
|
|
break;
|
|
case 0x0c:
|
|
lods(bits);
|
|
set_accum(bits, cpu_data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int do_print = 1;
|
|
|
|
static void
|
|
execvx0_0f(void)
|
|
{
|
|
uint8_t bit;
|
|
uint8_t odd;
|
|
uint8_t nibbles_count;
|
|
uint8_t destcmp;
|
|
uint8_t destbyte;
|
|
uint8_t srcbyte;
|
|
uint8_t nibble_result;
|
|
uint8_t temp_val;
|
|
uint8_t temp_al;
|
|
uint8_t bit_length;
|
|
uint8_t bit_offset;
|
|
int8_t nibble_result_s;
|
|
int bits;
|
|
uint32_t i;
|
|
uint32_t carry;
|
|
uint32_t nibble;
|
|
uint32_t srcseg;
|
|
uint32_t byteaddr;
|
|
|
|
switch (opcode) {
|
|
case 0x10: /* TEST1 r8/m8, CL*/
|
|
case 0x11: /* TEST1 r16/m16, CL*/
|
|
case 0x18: /* TEST1 r8/m8, imm3 */
|
|
case 0x19: /* TEST1 r16/m16, imm4 */
|
|
bits = 8 << (opcode & 0x1);
|
|
do_cycles(2);
|
|
|
|
bit = (opcode & 0x8) ? biu_pfq_fetchb() : CL;
|
|
bit &= ((1 << (3 + (opcode & 0x1))) - 1);
|
|
read_ea(0, bits);
|
|
|
|
set_zf_ex(!(cpu_data & (1 << bit)));
|
|
cpu_state.flags &= ~(V_FLAG | C_FLAG);
|
|
break;
|
|
|
|
case 0x12: /* CLR1 r8/m8, CL*/
|
|
case 0x13: /* CLR1 r16/m16, CL*/
|
|
case 0x1a: /* CLR1 r8/m8, imm3 */
|
|
case 0x1b: /* CLR1 r16/m16, imm4 */
|
|
bits = 8 << (opcode & 0x1);
|
|
do_cycles(2);
|
|
|
|
bit = (opcode & 0x8) ? biu_pfq_fetchb() : CL;
|
|
bit &= ((1 << (3 + (opcode & 0x1))) - 1);
|
|
read_ea(0, bits);
|
|
|
|
if (bits == 8)
|
|
seteab((cpu_data & 0xff) & ~(1 << bit));
|
|
else
|
|
seteaw((cpu_data & 0xffff) & ~(1 << bit));
|
|
break;
|
|
|
|
case 0x14: /* SET1 r8/m8, CL*/
|
|
case 0x15: /* SET1 r16/m16, CL*/
|
|
case 0x1c: /* SET1 r8/m8, imm3 */
|
|
case 0x1d: /* SET1 r16/m16, imm4 */
|
|
bits = 8 << (opcode & 0x1);
|
|
do_cycles(2);
|
|
|
|
bit = (opcode & 0x8) ? biu_pfq_fetchb() : CL;
|
|
bit &= ((1 << (3 + (opcode & 0x1))) - 1);
|
|
read_ea(0, bits);
|
|
|
|
if (bits == 8)
|
|
seteab((cpu_data & 0xff) | (1 << bit));
|
|
else
|
|
seteaw((cpu_data & 0xffff) | (1 << bit));
|
|
break;
|
|
|
|
case 0x16: /* NOT1 r8/m8, CL*/
|
|
case 0x17: /* NOT1 r16/m16, CL*/
|
|
case 0x1e: /* NOT1 r8/m8, imm3 */
|
|
case 0x1f: /* NOT1 r16/m16, imm4 */
|
|
bits = 8 << (opcode & 0x1);
|
|
do_cycles(2);
|
|
|
|
bit = (opcode & 0x8) ? (biu_pfq_fetchb()) : (CL);
|
|
bit &= ((1 << (3 + (opcode & 0x1))) - 1);
|
|
read_ea(0, bits);
|
|
|
|
if (bits == 8)
|
|
seteab((cpu_data & 0xff) ^ (1 << bit));
|
|
else
|
|
seteaw((cpu_data & 0xffff) ^ (1 << bit));
|
|
break;
|
|
|
|
case 0x20: /* ADD4S */
|
|
odd = !!(CL % 2);
|
|
zero = 1;
|
|
nibbles_count = CL - odd;
|
|
i = 0;
|
|
carry = 0;
|
|
nibble = 0;
|
|
srcseg = ovr_seg ? *ovr_seg : ds;
|
|
|
|
do_cycles(4);
|
|
|
|
for (i = 0; i < ((nibbles_count / 2) + odd); i++) {
|
|
do_cycles(19);
|
|
destcmp = read_mem_b((es) + DI + i);
|
|
|
|
for (nibble = 0; nibble < 2; nibble++) {
|
|
destbyte = destcmp >> (nibble ? 4 : 0);
|
|
srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0);
|
|
destbyte &= 0xF;
|
|
srcbyte &= 0xF;
|
|
nibble_result = (i == (nibbles_count / 2) && nibble == 1) ? (destbyte + carry) :
|
|
((uint8_t) (destbyte)) + ((uint8_t) (srcbyte)) + ((uint32_t) carry);
|
|
carry = 0;
|
|
|
|
while (nibble_result >= 10) {
|
|
nibble_result -= 10;
|
|
carry++;
|
|
}
|
|
|
|
if (zero != 0 || (i == (nibbles_count / 2) && nibble == 1))
|
|
zero = (nibble_result == 0);
|
|
|
|
destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result << (4 * nibble)));
|
|
}
|
|
|
|
write_mem_b(es + DI + i, destcmp);
|
|
}
|
|
|
|
set_cf(!!carry);
|
|
set_zf(!!zero);
|
|
break;
|
|
|
|
case 0x22: /* SUB4S */
|
|
odd = !!(CL % 2);
|
|
zero = 1;
|
|
nibbles_count = CL - odd;
|
|
i = 0;
|
|
carry = 0;
|
|
nibble = 0;
|
|
srcseg = ovr_seg ? *ovr_seg : ds;
|
|
|
|
do_cycles(4);
|
|
|
|
for (i = 0; i < ((nibbles_count / 2) + odd); i++) {
|
|
do_cycles(19);
|
|
destcmp = read_mem_b((es) + DI + i);
|
|
|
|
for (nibble = 0; nibble < 2; nibble++) {
|
|
destbyte = destcmp >> (nibble ? 4 : 0);
|
|
srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0);
|
|
destbyte &= 0xF;
|
|
srcbyte &= 0xF;
|
|
nibble_result_s = (i == (nibbles_count / 2) && nibble == 1) ? ((int8_t) destbyte - (int8_t) carry) :
|
|
((int8_t) (destbyte)) - ((int8_t) (srcbyte)) - ((int8_t) carry);
|
|
carry = 0;
|
|
|
|
while (nibble_result_s < 0) {
|
|
nibble_result_s += 10;
|
|
carry++;
|
|
}
|
|
|
|
if (zero != 0 || (i == (nibbles_count / 2) && nibble == 1))
|
|
zero = (nibble_result_s == 0);
|
|
|
|
destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result_s << (4 * nibble)));
|
|
}
|
|
|
|
write_mem_b(es + DI + i, destcmp);
|
|
}
|
|
|
|
set_cf(!!carry);
|
|
set_zf(!!zero);
|
|
break;
|
|
|
|
case 0x26: /* CMP4S */
|
|
odd = !!(CL % 2);
|
|
zero = 1;
|
|
nibbles_count = CL - odd;
|
|
i = 0;
|
|
carry = 0;
|
|
nibble = 0;
|
|
srcseg = ovr_seg ? *ovr_seg : ds;
|
|
|
|
do_cycles(4);
|
|
|
|
for (i = 0; i < ((nibbles_count / 2) + odd); i++) {
|
|
do_cycles(19);
|
|
destcmp = read_mem_b((es) + DI + i);
|
|
|
|
for (nibble = 0; nibble < 2; nibble++) {
|
|
destbyte = destcmp >> (nibble ? 4 : 0);
|
|
srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0);
|
|
destbyte &= 0xF;
|
|
srcbyte &= 0xF;
|
|
nibble_result_s = ((int8_t) (destbyte)) - ((int8_t) (srcbyte)) - ((int8_t) carry);
|
|
carry = 0;
|
|
|
|
while (nibble_result_s < 0) {
|
|
nibble_result_s += 10;
|
|
carry++;
|
|
}
|
|
|
|
if (zero != 0 || (i == (nibbles_count / 2) && nibble == 1))
|
|
zero = (nibble_result_s == 0);
|
|
|
|
destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result_s << (4 * nibble)));
|
|
}
|
|
}
|
|
|
|
set_cf(!!carry);
|
|
set_zf(!!zero);
|
|
break;
|
|
|
|
case 0x28: /* ROL4 r/m */
|
|
do_cycles(20);
|
|
|
|
temp_val = geteab();
|
|
temp_al = AL;
|
|
|
|
temp_al &= 0x0f;
|
|
temp_al |= (temp_val & 0xf0);
|
|
temp_val = (temp_al & 0x0f) | ((temp_val & 0x0f) << 4);
|
|
temp_al >>= 4;
|
|
temp_al &= 0x0f;
|
|
seteab(temp_val);
|
|
AL = temp_al;
|
|
break;
|
|
|
|
case 0x2a: /* ROR4 r/m */
|
|
do_cycles(20);
|
|
|
|
temp_val = geteab();
|
|
temp_al = AL;
|
|
|
|
AL = temp_val & 0x0f;
|
|
temp_val = (temp_val >> 4) | ((temp_al & 0x0f) << 4);
|
|
|
|
seteab(temp_val);
|
|
break;
|
|
|
|
case 0x31: /* INS reg1, reg2 */
|
|
case 0x39: /* INS reg8, imm4 */
|
|
bit_length = ((opcode & 0x8) ? (biu_pfq_fetchb() & 0x0f) : (getr8(cpu_reg) & 0x0f)) + 1;
|
|
bit_offset = getr8(cpu_rm) & 0x0f;
|
|
byteaddr = (es) + DI;
|
|
i = 0;
|
|
|
|
if (bit_offset >= 8) {
|
|
DI++;
|
|
byteaddr++;
|
|
bit_offset -= 8;
|
|
}
|
|
|
|
for (i = 0; i < bit_length; i++) {
|
|
byteaddr = (es) + DI;
|
|
writememb(es, DI, (read_mem_b(byteaddr) & ~(1 << (bit_offset))) | ((!!(AX & (1 << i))) << bit_offset));
|
|
bit_offset++;
|
|
|
|
if (bit_offset == 8) {
|
|
DI++;
|
|
bit_offset = 0;
|
|
}
|
|
}
|
|
|
|
setr8(cpu_rm, bit_offset);
|
|
break;
|
|
|
|
case 0x33: /* EXT reg1, reg2 */
|
|
case 0x3b: /* EXT reg8, imm4 */
|
|
bit_length = ((opcode & 0x8) ? (biu_pfq_fetchb() & 0x0f) : (getr8(cpu_reg) & 0x0f)) + 1;
|
|
bit_offset = getr8(cpu_rm) & 0x0f;
|
|
byteaddr = (ds) + SI;
|
|
i = 0;
|
|
|
|
if (bit_offset >= 8) {
|
|
SI++;
|
|
byteaddr++;
|
|
bit_offset -= 8;
|
|
}
|
|
|
|
AX = 0;
|
|
|
|
for (i = 0; i < bit_length; i++) {
|
|
byteaddr = (ds) + SI;
|
|
AX |= (!!(readmemb(ds, SI) & (1 << bit_offset))) << i;
|
|
bit_offset++;
|
|
|
|
if (bit_offset == 8) {
|
|
SI++;
|
|
bit_offset = 0;
|
|
}
|
|
}
|
|
|
|
setr8(cpu_rm, bit_offset);
|
|
break;
|
|
|
|
case 0xff: /* BRKEM */
|
|
interrupt_brkem(biu_pfq_fetchb());
|
|
break;
|
|
|
|
default:
|
|
do_cycles_nx_i(2); /* Guess, based on NOP. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
execvx0_6x(uint16_t *jump)
|
|
{
|
|
uint16_t lowbound;
|
|
uint16_t highbound;
|
|
uint16_t regval;
|
|
uint16_t wordtopush;
|
|
uint16_t immediate;
|
|
uint16_t tempw;
|
|
int bits;
|
|
int32_t templ;
|
|
|
|
switch (opcode) {
|
|
case 0x60: /* PUSHA/PUSH R */
|
|
writememw(ss, ((SP - 2) & 0xffff), AX);
|
|
biu_state_set_eu();
|
|
writememw(ss, ((SP - 4) & 0xffff), CX);
|
|
biu_state_set_eu();
|
|
writememw(ss, ((SP - 6) & 0xffff), DX);
|
|
biu_state_set_eu();
|
|
writememw(ss, ((SP - 8) & 0xffff), BX);
|
|
biu_state_set_eu();
|
|
writememw(ss, ((SP - 10) & 0xffff), SP);
|
|
biu_state_set_eu();
|
|
writememw(ss, ((SP - 12) & 0xffff), BP);
|
|
biu_state_set_eu();
|
|
writememw(ss, ((SP - 14) & 0xffff), SI);
|
|
biu_state_set_eu();
|
|
writememw(ss, ((SP - 16) & 0xffff), DI);
|
|
SP -= 16;
|
|
break;
|
|
|
|
case 0x61: /* POPA/POP R */
|
|
DI = readmemw(ss, ((SP) & 0xffff));
|
|
biu_state_set_eu();
|
|
SI = readmemw(ss, ((SP + 2) & 0xffff));
|
|
biu_state_set_eu();
|
|
BP = readmemw(ss, ((SP + 4) & 0xffff));
|
|
biu_state_set_eu();
|
|
BX = readmemw(ss, ((SP + 8) & 0xffff));
|
|
biu_state_set_eu();
|
|
DX = readmemw(ss, ((SP + 10) & 0xffff));
|
|
biu_state_set_eu();
|
|
CX = readmemw(ss, ((SP + 12) & 0xffff));
|
|
biu_state_set_eu();
|
|
AX = readmemw(ss, ((SP + 14) & 0xffff));
|
|
SP += 16;
|
|
break;
|
|
|
|
case 0x62: /* BOUND r/m */
|
|
lowbound = 0;
|
|
highbound = 0;
|
|
regval = 0;
|
|
|
|
lowbound = readmemw(easeg, cpu_state.eaaddr);
|
|
highbound = readmemw(easeg, cpu_state.eaaddr + 2);
|
|
regval = get_reg(cpu_reg);
|
|
|
|
if ((lowbound > regval) || (highbound < regval)) {
|
|
sw_int(5);
|
|
*jump = 1;
|
|
}
|
|
break;
|
|
|
|
case 0x63:
|
|
if (is_nec) {
|
|
/* read_operand16() */
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
tempw = cpu_state.pc;
|
|
geteaw();
|
|
do_cycles(60);
|
|
}
|
|
break;
|
|
|
|
case 0x64:
|
|
case 0x65:
|
|
if (!is_nec) {
|
|
do_cycles_nx_i(2); /* Guess, based on NOP. */
|
|
}
|
|
break;
|
|
|
|
case 0x66 ... 0x67: /* FPO2 - NEC FPU instructions. */
|
|
/* read_operand16() */
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
tempw = cpu_state.pc;
|
|
geteaw();
|
|
/* fpu_op() */
|
|
cpu_state.pc = tempw; /* Do this as the x87 code advances it, which is needed on
|
|
the 286+ core, but not here. */
|
|
break;
|
|
|
|
case 0x68:
|
|
wordtopush = biu_pfq_fetchw();
|
|
push(&wordtopush);
|
|
break;
|
|
|
|
case 0x69:
|
|
bits = 16;
|
|
read_ea(0, 16);
|
|
immediate = biu_pfq_fetchw();
|
|
|
|
templ = ((int) cpu_data) * ((int) immediate);
|
|
if ((templ >> 15) != 0 && (templ >> 15) != -1)
|
|
cpu_state.flags |= C_FLAG | V_FLAG;
|
|
else
|
|
cpu_state.flags &= ~(C_FLAG | V_FLAG);
|
|
set_reg(cpu_reg, templ & 0xffff);
|
|
do_cycles((cpu_mod == 3) ? 20 : 26);
|
|
break;
|
|
|
|
case 0x6a:
|
|
wordtopush = sign_extend(biu_pfq_fetchb());
|
|
push(&wordtopush);
|
|
break;
|
|
|
|
case 0x6b: /* IMUL reg16,reg16/mem16,imm8 */
|
|
read_ea(0, 16);
|
|
immediate = biu_pfq_fetchb();
|
|
immediate = geteaw();
|
|
if (immediate & 0x80)
|
|
immediate |= 0xff00;
|
|
|
|
templ = ((int) cpu_data) * ((int) immediate);
|
|
if ((templ >> 15) != 0 && (templ >> 15) != -1)
|
|
cpu_state.flags |= C_FLAG | V_FLAG;
|
|
else
|
|
cpu_state.flags &= ~(C_FLAG | V_FLAG);
|
|
set_reg(cpu_reg, templ & 0xffff);
|
|
do_cycles((cpu_mod == 3) ? 24 : 30);
|
|
break;
|
|
|
|
case 0x6c:
|
|
case 0x6d: /* INM dst, DW/INS dst, DX */
|
|
bits = 8 << (opcode & 1);
|
|
if (rep_start()) {
|
|
string_op(bits);
|
|
do_cycle_i();
|
|
|
|
if (in_rep != 0) {
|
|
completed = 0;
|
|
repeating = 1;
|
|
|
|
do_cycle_i();
|
|
if (irq_pending()) {
|
|
do_cycle_i();
|
|
rep_interrupt();
|
|
}
|
|
|
|
do_cycle_i();
|
|
/* decrement_register16() */
|
|
CX--;
|
|
if (CX == 0)
|
|
rep_end();
|
|
else
|
|
do_cycle_i();
|
|
} else
|
|
do_cycle_i();
|
|
}
|
|
break;
|
|
|
|
case 0x6e:
|
|
case 0x6f: /* OUTM DW, src/OUTS DX, src */
|
|
bits = 8 << (opcode & 1);
|
|
if (rep_start()) {
|
|
string_op(bits);
|
|
do_cycles_i(3);
|
|
|
|
if (in_rep != 0) {
|
|
completed = 0;
|
|
repeating = 1;
|
|
|
|
do_cycle_i();
|
|
/* decrement_register16() */
|
|
CX--;
|
|
|
|
if (irq_pending()) {
|
|
do_cycles_i(2);
|
|
rep_interrupt();
|
|
} else {
|
|
do_cycles_i(2);
|
|
|
|
if (CX == 0)
|
|
rep_end();
|
|
else
|
|
do_cycle_i();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
do_cycles_nx_i(2); /* Guess, based on NOP. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Executes a single instruction. */
|
|
void
|
|
execute_instruction(void)
|
|
{
|
|
uint8_t temp = 0;
|
|
uint8_t tempb;
|
|
uint8_t nests;
|
|
|
|
int8_t rel8;
|
|
int8_t temps;
|
|
|
|
uint16_t addr;
|
|
uint16_t jump = 0;
|
|
uint16_t new_cs;
|
|
uint16_t new_ip;
|
|
uint16_t tempw;
|
|
uint16_t zero_cond;
|
|
uint16_t old_cs;
|
|
uint16_t old_ip;
|
|
uint16_t old_flags;
|
|
uint16_t prod16;
|
|
uint16_t tempw_int;
|
|
uint16_t size;
|
|
uint16_t tempbp;
|
|
uint16_t src16;
|
|
|
|
int16_t rel16;
|
|
int16_t temps16;
|
|
|
|
uint32_t prod32;
|
|
uint32_t templ;
|
|
uint32_t templ2 = 0;
|
|
|
|
int bits;
|
|
int negate;
|
|
int tempws = 0;
|
|
int tempws2 = 0;
|
|
|
|
completed = 1;
|
|
|
|
if (nx) {
|
|
do_cycle();
|
|
nx = 0;
|
|
} else if (!modrm_loaded)
|
|
do_cycle();
|
|
|
|
if (group_delay) {
|
|
group_delay = 0;
|
|
do_cycle();
|
|
nx = 0;
|
|
}
|
|
|
|
if (!is_nec && (opcode >= 0xc0) && (opcode <= 0xc1))
|
|
opcode |= 0x02;
|
|
|
|
if (is_nec && !(cpu_state.flags & MD_FLAG)) {
|
|
i8080_step(&emulated_processor);
|
|
set_if(emulated_processor.iff);
|
|
if (retem)
|
|
jump = 1;
|
|
retem = 0;
|
|
do_cycles(emulated_processor.cyc);
|
|
emulated_processor.cyc = 0;
|
|
} else if (is_nec && in_0f)
|
|
execvx0_0f();
|
|
else if (is_nec && ((opcode & 0xf0) == 0x60))
|
|
execvx0_6x(&jump);
|
|
else switch (opcode) {
|
|
case 0x00: /* ADD r/m8, r8; r8, r/m8; al, imm8 */
|
|
case 0x02:
|
|
case 0x04:
|
|
case 0x08: /* OR r/m8, r8; r8, r/m8; al, imm8 */
|
|
case 0x0a:
|
|
case 0x0c:
|
|
case 0x10: /* ADC r/m8, r8; r8, r/m8; al, imm8 */
|
|
case 0x12:
|
|
case 0x14:
|
|
case 0x18: /* SBB r/m8, r8; r8, r/m8; al, imm8 */
|
|
case 0x1a:
|
|
case 0x1c:
|
|
case 0x20: /* AND r/m8, r8; r8, r/m8; al, imm8 */
|
|
case 0x22:
|
|
case 0x24:
|
|
case 0x28: /* SUB r/m8, r8; r8, r/m8; al, imm8 */
|
|
case 0x2a:
|
|
case 0x2c:
|
|
case 0x30: /* XOR r/m8, r8; r8, r/m8; al, imm8 */
|
|
case 0x32:
|
|
case 0x34:
|
|
bits = 8;
|
|
/* read_operand8() */
|
|
if (opcode & 0x04) {
|
|
cpu_data = biu_pfq_fetch();
|
|
cpu_dest = get_accum(bits); /* AX/AL */
|
|
cpu_src = cpu_data;
|
|
} else {
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
tempw = get_ea();
|
|
if (opcode & 2) {
|
|
cpu_dest = get_reg(cpu_reg);
|
|
cpu_src = tempw;
|
|
} else {
|
|
cpu_dest = tempw;
|
|
cpu_src = get_reg(cpu_reg);
|
|
}
|
|
}
|
|
do_cycles_nx_i(2);
|
|
if (!(opcode & 0x06) && (cpu_mod != 3))
|
|
do_cycles_i(2);
|
|
|
|
/* math_op8() */
|
|
math_op((opcode >> 3) & 7);
|
|
/* write_operand8() */
|
|
if (opcode & 0x04)
|
|
set_accum(bits, cpu_data);
|
|
else {
|
|
if (opcode & 2)
|
|
set_reg(cpu_reg, cpu_data);
|
|
else
|
|
set_ea(cpu_data);
|
|
}
|
|
break;
|
|
|
|
case 0x01: /* ADD r/m16, r16; r16, r/m16; ax, imm16 */
|
|
case 0x03:
|
|
case 0x05:
|
|
case 0x09: /* OR r/m16, r16; r16, r/m16; ax, imm16 */
|
|
case 0x0b:
|
|
case 0x0d:
|
|
case 0x11: /* ADC r/m16, r16; r16, r/m16; ax, imm16 */
|
|
case 0x13:
|
|
case 0x15:
|
|
case 0x19: /* SBB r/m16, r16; r16, r/m16; ax, imm16 */
|
|
case 0x1b:
|
|
case 0x1d:
|
|
case 0x21: /* AND r/m16, r16; r16, r/m16; ax, imm16 */
|
|
case 0x23:
|
|
case 0x25:
|
|
case 0x29: /* SUB r/m16, r16; r16, r/m16; ax, imm16 */
|
|
case 0x2b:
|
|
case 0x2d:
|
|
case 0x31: /* XOR r/m16, r16; r16, r/m16; ax, imm16 */
|
|
case 0x33:
|
|
case 0x35:
|
|
bits = 16;
|
|
nx = 1;
|
|
/* read_operand16() */
|
|
if (opcode & 0x04) {
|
|
cpu_data = biu_pfq_fetch();
|
|
cpu_dest = get_accum(bits); /* AX/AL */
|
|
cpu_src = cpu_data;
|
|
} else {
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(is_nec ? 1 : 2); /* load_operand() */
|
|
tempw = get_ea();
|
|
if (opcode & 2) {
|
|
cpu_dest = get_reg(cpu_reg);
|
|
cpu_src = tempw;
|
|
} else {
|
|
cpu_dest = tempw;
|
|
cpu_src = get_reg(cpu_reg);
|
|
}
|
|
}
|
|
do_cycles_nx_i(2);
|
|
if (!(opcode & 0x06) && (cpu_mod != 3))
|
|
do_cycles_i(2);
|
|
|
|
/* math_op16() */
|
|
math_op((opcode >> 3) & 7);
|
|
/* write_operand16() */
|
|
if (opcode & 0x04)
|
|
set_accum(bits, cpu_data);
|
|
else {
|
|
if (opcode & 0x02)
|
|
set_reg(cpu_reg, cpu_data);
|
|
else
|
|
set_ea(cpu_data);
|
|
}
|
|
break;
|
|
|
|
case 0x06:
|
|
case 0x0e:
|
|
case 0x16:
|
|
case 0x1e: /* PUSH seg */
|
|
do_cycles_i(3);
|
|
push(&(_opseg[(opcode >> 3) & 0x03]->seg));
|
|
break;
|
|
|
|
case 0x07:
|
|
case 0x17:
|
|
case 0x1f: /* POP seg */
|
|
load_seg(pop(), _opseg[(opcode >> 3) & 0x03]);
|
|
/* All POP segment instructions suppress interrupts for one instruction. */
|
|
noint = 1;
|
|
break;
|
|
|
|
case 0x0f:
|
|
if (!is_nec) {
|
|
load_cs(pop());
|
|
/* All POP segment instructions suppress interrupts for one instruction. */
|
|
noint = 1;
|
|
}
|
|
break;
|
|
|
|
case 0x26: /* ES: */
|
|
case 0x2e: /* CS: */
|
|
case 0x36: /* SS: */
|
|
case 0x3e: /* DS: */
|
|
break;
|
|
|
|
case 0x27: /* DAA */
|
|
do_cycles_nx_i(3);
|
|
daa();
|
|
break;
|
|
|
|
case 0x2f: /* DAS */
|
|
do_cycles_nx_i(3);
|
|
das();
|
|
break;
|
|
|
|
case 0x37: /* AAA */
|
|
aaa();
|
|
break;
|
|
|
|
case 0x38: /* CMP r/m8, r8; r8, r/m8; al, imm8 */
|
|
case 0x3a:
|
|
case 0x3c:
|
|
bits = 8;
|
|
/* read_operand8() */
|
|
if (opcode & 0x04) {
|
|
cpu_data = biu_pfq_fetch();
|
|
cpu_dest = get_accum(bits); /* AX/AL */
|
|
cpu_src = cpu_data;
|
|
} else {
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
tempw = get_ea();
|
|
if (opcode & 2) {
|
|
cpu_dest = get_reg(cpu_reg);
|
|
cpu_src = tempw;
|
|
} else {
|
|
cpu_dest = tempw;
|
|
cpu_src = get_reg(cpu_reg);
|
|
}
|
|
}
|
|
|
|
do_cycles_nx_i(2);
|
|
|
|
/* math_op8() */
|
|
math_op(7);
|
|
break;
|
|
|
|
case 0x39: /* CMP r/m16, r16; r16, r/m16; ax, imm16 */
|
|
case 0x3b:
|
|
case 0x3d:
|
|
bits = 16;
|
|
/* read_operand16() */
|
|
if (opcode & 0x04) {
|
|
cpu_data = biu_pfq_fetch();
|
|
cpu_dest = get_accum(bits); /* AX/AL */
|
|
cpu_src = cpu_data;
|
|
} else {
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
tempw = get_ea();
|
|
if (opcode & 2) {
|
|
cpu_dest = get_reg(cpu_reg);
|
|
cpu_src = tempw;
|
|
} else {
|
|
cpu_dest = tempw;
|
|
cpu_src = get_reg(cpu_reg);
|
|
}
|
|
}
|
|
|
|
do_cycles_nx_i((opcode == 0x3d) ? 1 : 2);
|
|
|
|
/* math_op16() */
|
|
math_op(7);
|
|
break;
|
|
|
|
case 0x3f: /*AAS*/
|
|
aas();
|
|
break;
|
|
|
|
case 0x40 ... 0x47: /* INC r16 */
|
|
/* read_operand16() */
|
|
cpu_dest = cpu_state.regs[opcode & 7].w;
|
|
cpu_src = 1;
|
|
bits = 16;
|
|
/* math_op16() */
|
|
cpu_data = cpu_dest + cpu_src;
|
|
set_of_add(bits);
|
|
do_af();
|
|
set_pzs(16);
|
|
/* write_operand16() */
|
|
cpu_state.regs[opcode & 7].w = cpu_data;
|
|
|
|
do_cycles_nx(1);
|
|
break;
|
|
|
|
case 0x48 ... 0x4f: /* DEC r16 */
|
|
/* read_operand16() */
|
|
cpu_dest = cpu_state.regs[opcode & 7].w;
|
|
cpu_src = 1;
|
|
bits = 16;
|
|
/* math_op16() */
|
|
cpu_data = cpu_dest - cpu_src;
|
|
set_of_sub(bits);
|
|
do_af();
|
|
set_pzs(16);
|
|
/* write_operand16() */
|
|
cpu_state.regs[opcode & 7].w = cpu_data;
|
|
|
|
do_cycles_nx(1);
|
|
break;
|
|
|
|
case 0x50 ... 0x57: /* PUSH r16 */
|
|
do_cycles_i(3);
|
|
|
|
push(&(cpu_state.regs[opcode & 0x07].w));
|
|
break;
|
|
|
|
case 0x58 ... 0x5f: /* POP r16 */
|
|
cpu_state.regs[opcode & 0x07].w = pop();
|
|
do_cycle_nx_i();
|
|
break;
|
|
|
|
case 0x60 ... 0x7f: /* JMP rel8 */
|
|
switch ((opcode >> 1) & 0x07) {
|
|
case 0x00:
|
|
jump = cpu_state.flags & V_FLAG;
|
|
break;
|
|
case 0x01:
|
|
jump = cpu_state.flags & C_FLAG;
|
|
break;
|
|
case 0x02:
|
|
jump = cpu_state.flags & Z_FLAG;
|
|
break;
|
|
case 0x03:
|
|
jump = cpu_state.flags & (C_FLAG | Z_FLAG);
|
|
break;
|
|
case 0x04:
|
|
jump = cpu_state.flags & N_FLAG;
|
|
break;
|
|
case 0x05:
|
|
jump = cpu_state.flags & P_FLAG;
|
|
break;
|
|
case 0x06:
|
|
jump = (!!(cpu_state.flags & N_FLAG)) != (!!(cpu_state.flags & V_FLAG));
|
|
break;
|
|
case 0x07:
|
|
jump = (cpu_state.flags & Z_FLAG) ||
|
|
((!!(cpu_state.flags & N_FLAG)) != (!!(cpu_state.flags & V_FLAG)));
|
|
break;
|
|
}
|
|
if (opcode & 1)
|
|
jump = !jump;
|
|
|
|
rel8 = (int8_t) biu_pfq_fetchb();
|
|
new_ip = cpu_state.pc + rel8;
|
|
if (!is_nec)
|
|
do_cycle_i();
|
|
|
|
if (jump)
|
|
reljmp(new_ip, 1);
|
|
break;
|
|
|
|
case 0x80: /* ADD/OR/ADC/SBB/AND/SUB/XOR/CMP r/m8, imm8 */
|
|
case 0x82:
|
|
bits = 8;
|
|
/* read_opreand8() */
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
cpu_data = get_ea();
|
|
cpu_dest = cpu_data;
|
|
cpu_src = biu_pfq_fetchb() | 0xff00;
|
|
|
|
do_cycle_nx();
|
|
math_op((rmdat & 0x38) >> 3);
|
|
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2);
|
|
|
|
/* write_operand8() */
|
|
if (cpu_alu_op != 7)
|
|
set_ea(cpu_data);
|
|
break;
|
|
|
|
case 0x81: /* ADD/OR/ADC/SBB/AND/SUB/XOR/CMP r/m16, imm16 */
|
|
bits = 16;
|
|
/* read_opreand16() */
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
cpu_data = get_ea();
|
|
cpu_dest = cpu_data;
|
|
cpu_src = biu_pfq_fetchw();
|
|
|
|
do_cycle_nx();
|
|
math_op((rmdat & 0x38) >> 3);
|
|
|
|
if (cpu_mod != 3) {
|
|
if (cpu_alu_op != 7)
|
|
do_cycles_i(2);
|
|
else {
|
|
do_cycles_nx_i(2);
|
|
}
|
|
}
|
|
|
|
/* write_operand16() */
|
|
if (cpu_alu_op != 7)
|
|
set_ea(cpu_data);
|
|
break;
|
|
|
|
case 0x83: /* ADD/OR/ADC/SBB/AND/SUB/XOR/CMP r/m16, imm8 (sign-extended) */
|
|
bits = 16;
|
|
/* read_opreand16() */
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
cpu_data = get_ea();
|
|
cpu_dest = cpu_data;
|
|
cpu_src = sign_extend(biu_pfq_fetchb());
|
|
|
|
do_cycle_nx();
|
|
math_op((rmdat & 0x38) >> 3);
|
|
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2);
|
|
|
|
/* write_operand16() */
|
|
if (cpu_alu_op != 7)
|
|
set_ea(cpu_data);
|
|
break;
|
|
|
|
case 0x84: /* TEST r/m8, r8 */
|
|
bits = 8;
|
|
/* read_operand8() */
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
cpu_data = get_ea();
|
|
|
|
/* math_op8() */
|
|
test(bits, cpu_data, get_reg(cpu_reg));
|
|
|
|
do_cycles_nx_i(2);
|
|
break;
|
|
|
|
case 0x85: /* TEST r/m16, r16 */
|
|
bits = 16;
|
|
/* read_operand16() */
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
cpu_data = get_ea();
|
|
|
|
/* math_op16() */
|
|
test(bits, cpu_data, get_reg(cpu_reg));
|
|
|
|
do_cycles_nx_i(2);
|
|
break;
|
|
|
|
case 0x86: /* XHG r8, r/m8 */
|
|
bits = 8;
|
|
/* read_operand8() */
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
cpu_data = get_ea();
|
|
cpu_src = get_reg(cpu_reg);
|
|
|
|
do_cycles_nx(3);
|
|
|
|
if (cpu_mod != 3)
|
|
do_cycles(2);
|
|
|
|
/* write_operand8() */
|
|
set_reg(cpu_reg, cpu_data);
|
|
set_ea(cpu_src);
|
|
break;
|
|
|
|
case 0x87: /* XCHG r16, r/m16 */
|
|
bits = 16;
|
|
/* read_operand16() */
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
cpu_data = get_ea();
|
|
cpu_src = get_reg(cpu_reg);
|
|
|
|
do_cycles_nx(3);
|
|
|
|
if (cpu_mod != 3)
|
|
do_cycles(2);
|
|
|
|
/* write_operand16() */
|
|
set_reg(cpu_reg, cpu_data);
|
|
set_ea(cpu_src);
|
|
break;
|
|
|
|
case 0x88: /* MOV r/m8, r8; MOV r8, r/m8 */
|
|
case 0x8a:
|
|
bits = 8;
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
do_cycle_nx();
|
|
/* read_operand8() */
|
|
if (opcode == 0x88)
|
|
tempb = get_reg(cpu_reg);
|
|
else
|
|
tempb = get_ea();
|
|
|
|
if ((opcode == 0x88) && (cpu_mod != 3))
|
|
do_cycles_i(2);
|
|
|
|
/* write_operand8() */
|
|
if (opcode == 0x88)
|
|
set_ea(tempb);
|
|
else
|
|
set_reg(cpu_reg, tempb);
|
|
break;
|
|
|
|
case 0x89: /* MOV r/m16, r16; MOV r16, r/m16 */
|
|
case 0x8b:
|
|
bits = 16;
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
do_cycle_nx();
|
|
/* read_operand16() */
|
|
if (opcode == 0x89)
|
|
tempw = get_reg(cpu_reg);
|
|
else
|
|
tempw = get_ea();
|
|
|
|
if ((opcode == 0x89) && (cpu_mod != 3))
|
|
do_cycles_i(2);
|
|
|
|
/* write_operand16() */
|
|
if (opcode == 0x89)
|
|
set_ea(tempw);
|
|
else
|
|
set_reg(cpu_reg, tempw);
|
|
break;
|
|
|
|
case 0x8c: /* MOV r/m16, SReg; MOV SReg, r/m16 */
|
|
case 0x8e:
|
|
bits = 16;
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
if ((opcode == 0x8c) && (cpu_mod != 3))
|
|
do_cycle_i();
|
|
/* read_operand16() */
|
|
if (opcode == 0x8c)
|
|
tempw = _opseg[(rmdat & 0x18) >> 3]->seg;
|
|
else
|
|
tempw = geteaw();
|
|
/* write_operand16() */
|
|
if (opcode == 0x8c)
|
|
seteaw(tempw);
|
|
else {
|
|
if ((rmdat & 0x18) == 0x08)
|
|
load_cs(tempw);
|
|
else
|
|
load_seg(tempw, _opseg[(rmdat & 0x18) >> 3]);
|
|
if (((rmdat & 0x18) >> 3) == 2)
|
|
noint = 1;
|
|
}
|
|
break;
|
|
|
|
case 0x8d: /* LEA */
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
cpu_state.regs[cpu_reg].w = cpu_state.eaaddr;
|
|
break;
|
|
|
|
case 0x8f: /* POP r/m16 */
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
do_cycle_i();
|
|
/* pop_u16() */
|
|
cpu_src = cpu_state.eaaddr;
|
|
cpu_data = pop();
|
|
do_cycle_i();
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2);
|
|
/* write_operand16() */
|
|
cpu_state.eaaddr = cpu_src;
|
|
seteaw(cpu_data);
|
|
break;
|
|
|
|
case 0x90 ... 0x97: /* XCHG AX, r */
|
|
cpu_data = cpu_state.regs[opcode & 7].w;
|
|
do_cycles_nx_i(2);
|
|
cpu_state.regs[opcode & 7].w = AX;
|
|
AX = cpu_data;
|
|
break;
|
|
|
|
case 0x98: /* CBW */
|
|
sign_extend_al();
|
|
break;
|
|
|
|
case 0x99: /* CWD */
|
|
sign_extend_ax();
|
|
break;
|
|
|
|
case 0x9a: /* CALLF */
|
|
/* read_operand_faraddr() */
|
|
new_ip = biu_pfq_fetchw();
|
|
new_cs = biu_pfq_fetchw();
|
|
|
|
farcall(new_cs, new_ip, 1);
|
|
|
|
jump = 1;
|
|
break;
|
|
|
|
case 0x9b: /* WAIT */
|
|
do_cycles(3);
|
|
break;
|
|
|
|
case 0x9c: /* PUSHF */
|
|
do_cycles(3);
|
|
/* push_flags() */
|
|
if (is_nec)
|
|
tempw = (cpu_state.flags & 0x8fd7) | 0x7000;
|
|
else
|
|
tempw = (cpu_state.flags & 0x0fd7) | 0xf000;
|
|
push(&tempw);
|
|
break;
|
|
|
|
case 0x9d: /* POPF */
|
|
/* pop_flags() */
|
|
if (is_nec && cpu_md_write_disable)
|
|
cpu_state.flags = pop() | 0x8002;
|
|
else
|
|
cpu_state.flags = pop() | 0x0002;
|
|
sync_to_i8080();
|
|
break;
|
|
|
|
case 0x9e: /* SAHF */
|
|
/* store_flags() */
|
|
cpu_state.flags = (cpu_state.flags & 0xff02) | AH;
|
|
break;
|
|
|
|
case 0x9f: /*LAHF*/
|
|
/* load_flags() */
|
|
/* set_register8() */
|
|
AH = cpu_state.flags & 0xd7;
|
|
break;
|
|
|
|
case 0xa0: /* MOV al, offset8 */
|
|
bits = 8;
|
|
/* read_operand8() */
|
|
cpu_state.eaaddr = biu_pfq_fetchw();
|
|
tempb = readmem(ovr_seg ? *ovr_seg : ds);
|
|
/* set_register8() */
|
|
set_accum(bits, tempb);
|
|
break;
|
|
|
|
case 0xa1: /* MOV al, offset16 */
|
|
bits = 16;
|
|
/* read_operand16() */
|
|
cpu_state.eaaddr = biu_pfq_fetchw();
|
|
tempw = readmem(ovr_seg ? *ovr_seg : ds);
|
|
/* set_register16() */
|
|
set_accum(bits, tempw);
|
|
break;
|
|
|
|
case 0xa2: /* MOV offset8, Al */
|
|
bits = 8;
|
|
tempb = get_accum(bits);
|
|
/* write_operand8() */
|
|
cpu_state.eaaddr = biu_pfq_fetchw();
|
|
writemem((ovr_seg ? *ovr_seg : ds), tempb);
|
|
break;
|
|
|
|
case 0xa3: /* MOV offset16, AX */
|
|
bits = 16;
|
|
tempw = get_accum(bits);
|
|
/* write_operand16() */
|
|
cpu_state.eaaddr = biu_pfq_fetchw();
|
|
writemem((ovr_seg ? *ovr_seg : ds), tempw);
|
|
break;
|
|
|
|
case 0xa4: /* MOVSB & MOVSW */
|
|
case 0xa5:
|
|
bits = 8 << (opcode & 1);
|
|
|
|
if (rep_start()) {
|
|
string_op(bits);
|
|
do_cycle_i();
|
|
|
|
if (in_rep != 0) {
|
|
completed = 0;
|
|
repeating = 1;
|
|
|
|
/* decrement_register16() */
|
|
CX--;
|
|
|
|
if (irq_pending()) {
|
|
do_cycles_i(2);
|
|
rep_interrupt();
|
|
} else {
|
|
do_cycles_i(2);
|
|
|
|
if (CX == 0)
|
|
rep_end();
|
|
else
|
|
do_cycle_i();
|
|
}
|
|
} else
|
|
do_cycle_i();
|
|
}
|
|
break;
|
|
|
|
case 0xa6: /* CMPSB, CMPSW, SCASB, SCASW */
|
|
case 0xa7:
|
|
case 0xae:
|
|
case 0xaf:
|
|
bits = 8 << (opcode & 1);
|
|
if (rep_start()) {
|
|
string_op(bits);
|
|
|
|
if (in_rep) {
|
|
uint8_t end = 0;
|
|
|
|
completed = 0;
|
|
repeating = 1;
|
|
|
|
do_cycle_i();
|
|
/* decrement_register16() */
|
|
CX--;
|
|
|
|
if ((!!(cpu_state.flags & (rep_c_flag ? C_FLAG : Z_FLAG))) == (in_rep == 1)) {
|
|
rep_end();
|
|
do_cycle_i();
|
|
end = 1;
|
|
}
|
|
|
|
if (!end) {
|
|
do_cycle_i();
|
|
|
|
if (irq_pending()) {
|
|
do_cycle_i();
|
|
rep_interrupt();
|
|
}
|
|
|
|
do_cycle_i();
|
|
if (CX == 0)
|
|
rep_end();
|
|
else
|
|
do_cycle_i();
|
|
} else
|
|
do_cycle_i();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0xa8: /* TEST al, imm8 */
|
|
bits = 8;
|
|
/* read_operand8() */
|
|
cpu_data = biu_pfq_fetch();
|
|
/* math_op8() */
|
|
test(bits, get_accum(bits), cpu_data);
|
|
break;
|
|
|
|
case 0xa9: /* TEST ax, imm16 */
|
|
bits = 16;
|
|
/* read_operand16() */
|
|
cpu_data = biu_pfq_fetch();
|
|
/* math_op16() */
|
|
test(bits, get_accum(bits), cpu_data);
|
|
break;
|
|
|
|
case 0xaa: /* STOSB & STOSW */
|
|
case 0xab:
|
|
bits = 8 << (opcode & 1);
|
|
if (rep_start()) {
|
|
string_op(bits);
|
|
do_cycle_i();
|
|
|
|
if (in_rep != 0) {
|
|
completed = 0;
|
|
repeating = 1;
|
|
|
|
do_cycle_i();
|
|
if (irq_pending()) {
|
|
do_cycle_i();
|
|
rep_interrupt();
|
|
}
|
|
|
|
do_cycle_i();
|
|
/* decrement_register16() */
|
|
CX--;
|
|
if (CX == 0)
|
|
rep_end();
|
|
else
|
|
do_cycle_i();
|
|
} else
|
|
do_cycle_i();
|
|
}
|
|
break;
|
|
|
|
case 0xac: /* LODSB * LODSW */
|
|
case 0xad:
|
|
bits = 8 << (opcode & 1);
|
|
if (rep_start()) {
|
|
string_op(bits);
|
|
do_cycles_i(3);
|
|
|
|
if (in_rep != 0) {
|
|
completed = 0;
|
|
repeating = 1;
|
|
|
|
do_cycle_i();
|
|
/* decrement_register16() */
|
|
CX--;
|
|
|
|
if (irq_pending()) {
|
|
do_cycles_i(2);
|
|
rep_interrupt();
|
|
} else {
|
|
do_cycles_i(2);
|
|
|
|
if (CX == 0)
|
|
rep_end();
|
|
else
|
|
do_cycle_i();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0xb0 ... 0xb7: /* MOV r8, imm8 */
|
|
bits = 8;
|
|
/* read_operand8() */
|
|
tempb = biu_pfq_fetchb();
|
|
/* set_register8() */
|
|
if (opcode & 0x04)
|
|
cpu_state.regs[opcode & 0x03].b.h = tempb;
|
|
else
|
|
cpu_state.regs[opcode & 0x03].b.l = tempb;
|
|
do_cycle_i();
|
|
break;
|
|
|
|
case 0xb8 ... 0xbf: /* MOV r16, imm16 */
|
|
bits = 16;
|
|
/* read_operand16() */
|
|
tempw = biu_pfq_fetchw();
|
|
/* set_register16() */
|
|
cpu_state.regs[opcode & 0x07].w = tempw;
|
|
break;
|
|
|
|
case 0xc0: /* rot imm8 */
|
|
case 0xc1:
|
|
/* rot rm */
|
|
bits = 8 << (opcode & 1);
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(is_nec ? 1 : 2); /* load_operand() */
|
|
/* read_operand() */
|
|
cpu_data = get_ea();
|
|
cpu_src = biu_pfq_fetchb();
|
|
if (is186 && !is_nec)
|
|
cpu_src &= 0x1F;
|
|
do_cycles_i(6);
|
|
if (cpu_src > 0) {
|
|
for (uint8_t i = 0; i < cpu_src; i++)
|
|
do_cycles_i(4);
|
|
}
|
|
if (cpu_mod != 3)
|
|
do_cycle_i();
|
|
/* bitshift_op() */
|
|
while (cpu_src != 0) {
|
|
cpu_dest = cpu_data;
|
|
oldc = cpu_state.flags & C_FLAG;
|
|
switch (rmdat & 0x38) {
|
|
case 0x00: /* ROL */
|
|
set_cf(top_bit(cpu_data, bits));
|
|
cpu_data <<= 1;
|
|
cpu_data |= ((cpu_state.flags & C_FLAG) ? 1 : 0);
|
|
set_of_rotate(bits);
|
|
set_af(0);
|
|
break;
|
|
case 0x08: /* ROR */
|
|
set_cf((cpu_data & 1) != 0);
|
|
cpu_data >>= 1;
|
|
if (cpu_state.flags & C_FLAG)
|
|
cpu_data |= (!(opcode & 1) ? 0x80 : 0x8000);
|
|
set_of_rotate(bits);
|
|
set_af(0);
|
|
break;
|
|
case 0x10: /* RCL */
|
|
set_cf(top_bit(cpu_data, bits));
|
|
cpu_data = (cpu_data << 1) | (oldc ? 1 : 0);
|
|
set_of_rotate(bits);
|
|
set_af(0);
|
|
break;
|
|
case 0x18: /* RCR */
|
|
set_cf((cpu_data & 1) != 0);
|
|
cpu_data >>= 1;
|
|
if (oldc)
|
|
cpu_data |= (!(opcode & 0x01) ? 0x80 : 0x8000);
|
|
set_cf((cpu_dest & 1) != 0);
|
|
set_of_rotate(bits);
|
|
set_af(0);
|
|
break;
|
|
case 0x20: /* SHL */
|
|
set_cf(top_bit(cpu_data, bits));
|
|
cpu_data <<= 1;
|
|
set_of_rotate(bits);
|
|
set_af((cpu_data & 0x10) != 0);
|
|
set_pzs(bits);
|
|
break;
|
|
case 0x28: /* SHR */
|
|
set_cf((cpu_data & 1) != 0);
|
|
cpu_data >>= 1;
|
|
set_of_rotate(bits);
|
|
set_af(0);
|
|
set_pzs(bits);
|
|
break;
|
|
case 0x30: /* SETMO - undocumented? */
|
|
bitwise(bits, 0xffff);
|
|
set_cf(0);
|
|
set_of_rotate(bits);
|
|
set_af(0);
|
|
set_pzs(bits);
|
|
break;
|
|
case 0x38: /* SAR */
|
|
set_cf((cpu_data & 1) != 0);
|
|
cpu_data >>= 1;
|
|
if (!(opcode & 1))
|
|
cpu_data |= (cpu_dest & 0x80);
|
|
else
|
|
cpu_data |= (cpu_dest & 0x8000);
|
|
set_of_rotate(bits);
|
|
set_af(0);
|
|
set_pzs(bits);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
--cpu_src;
|
|
}
|
|
|
|
if (opcode <= 0xd1) {
|
|
if (cpu_mod != 3)
|
|
do_cycle_i();
|
|
}
|
|
|
|
/* write_operand() */
|
|
set_ea(cpu_data);
|
|
break;
|
|
|
|
case 0xc2: /* RETN imm16 */
|
|
bits = 8;
|
|
cpu_src = biu_pfq_fetchw();
|
|
do_cycle_i();
|
|
new_ip = pop();
|
|
biu_suspend_fetch();
|
|
set_ip(new_ip);
|
|
|
|
do_cycles_i(2);
|
|
biu_queue_flush();
|
|
do_cycles_i(3);
|
|
|
|
/* release() */
|
|
SP += cpu_src;
|
|
|
|
jump = 1;
|
|
break;
|
|
|
|
case 0xc3: /* RETN */
|
|
bits = 8;
|
|
new_ip = pop();
|
|
biu_suspend_fetch();
|
|
set_ip(new_ip);
|
|
do_cycle_i();
|
|
biu_queue_flush();
|
|
do_cycles_i(2);
|
|
|
|
jump = 1;
|
|
break;
|
|
|
|
case 0xc4: /* LES */
|
|
case 0xc5: /* LDS */
|
|
bits = 16;
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
|
|
do_cycles_i(2);
|
|
|
|
/* read_operand_farptr() */
|
|
read_ea(1, bits);
|
|
cpu_state.regs[cpu_reg].w = cpu_data;
|
|
read_ea2(bits);
|
|
|
|
/* write_operand16() */
|
|
load_seg(cpu_data, (opcode & 0x01) ? &cpu_state.seg_ds : &cpu_state.seg_es);
|
|
break;
|
|
|
|
case 0xc6: /* MOV r/m8, imm8 */
|
|
bits = 8;
|
|
/* read_operand8() */
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
cpu_data = biu_pfq_fetch();
|
|
do_cycles(2);
|
|
/* write_operand8() */
|
|
set_ea(cpu_data);
|
|
break;
|
|
|
|
case 0xc7: /* MOV r/m16, imm16 */
|
|
bits = 16;
|
|
/* read_operand16() */
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
cpu_data = biu_pfq_fetch();
|
|
do_cycle_i();
|
|
/* write_operand16() */
|
|
set_ea(cpu_data);
|
|
break;
|
|
|
|
case 0xc8: /* RETF imm16 */
|
|
if (is_nec) {
|
|
/* ENTER/PREPARE */
|
|
tempw_int = 0;
|
|
size = biu_pfq_fetchw();
|
|
nests = biu_pfq_fetchb();
|
|
|
|
push(&BP);
|
|
tempw_int = SP;
|
|
if (nests > 0) {
|
|
while (--nests) {
|
|
tempbp = 0;
|
|
BP -= 2;
|
|
tempbp = readmemw(ss, BP);
|
|
push(&tempbp);
|
|
}
|
|
push(&tempw_int);
|
|
}
|
|
BP = tempw_int;
|
|
SP -= size;
|
|
break;
|
|
} else
|
|
fallthrough;
|
|
case 0xca:
|
|
bits = 16;
|
|
/* read_operand16() */
|
|
cpu_src = biu_pfq_fetchw();
|
|
farret(1);
|
|
/* release() */
|
|
SP += cpu_src;
|
|
do_cycle_i();
|
|
jump = 1;
|
|
break;
|
|
|
|
case 0xc9: /* RETF */
|
|
if (is_nec) {
|
|
/* LEAVE/DISPOSE */
|
|
SP = BP;
|
|
BP = pop();
|
|
break;
|
|
} else
|
|
fallthrough;
|
|
case 0xcb:
|
|
bits = 16;
|
|
do_cycle_i();
|
|
farret(1);
|
|
jump = 1;
|
|
break;
|
|
|
|
case 0xcc: /* INT 3 */
|
|
do_cycles_i(4);
|
|
int3();
|
|
jump = 1;
|
|
break;
|
|
|
|
case 0xcd: /* INT imm8 */
|
|
/* read_operand8() */
|
|
temp = biu_pfq_fetchb();
|
|
do_cycle_i();
|
|
sw_int(temp);
|
|
jump = 1;
|
|
break;
|
|
|
|
case 0xce: /* INTO */
|
|
if (cpu_state.flags & V_FLAG) {
|
|
sw_int(4);
|
|
jump = 1;
|
|
}
|
|
break;
|
|
|
|
case 0xcf: /* IRET */
|
|
iret_routine();
|
|
if (is_nec && !(cpu_state.flags & MD_FLAG))
|
|
sync_to_i8080();
|
|
jump = 1;
|
|
break;
|
|
|
|
case 0xd0: /* ROL, ROR, RCL, RCR, SHL, SHR, SAR: r/m 8, 0x01 */
|
|
case 0xd1: /* ROL, ROR, RCL, RCR, SHL, SHR, SAR: r/m 16, 0x01 */
|
|
case 0xd2: /* ROL, ROR, RCL, RCR, SHL, SHR, SAR: r/m 8, cl */
|
|
case 0xd3: /* ROL, ROR, RCL, RCR, SHL, SHR, SAR: r/m 16, cl */
|
|
/* rot rm */
|
|
bits = 8 << (opcode & 1);
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(is_nec ? 1 : 2); /* load_operand() */
|
|
/* read_operand() */
|
|
cpu_data = get_ea();
|
|
if ((opcode & 2) == 0)
|
|
cpu_src = 1;
|
|
else
|
|
cpu_src = CL;
|
|
if (is186 && !is_nec)
|
|
cpu_src &= 0x1F;
|
|
if (opcode >= 0xd2) {
|
|
do_cycles_i(6);
|
|
if (CL > 0) {
|
|
for (uint8_t i = 0; i < CL; i++)
|
|
do_cycles_i(4);
|
|
}
|
|
if (cpu_mod != 3)
|
|
do_cycle_i();
|
|
}
|
|
/* bitshift_op() */
|
|
while (cpu_src != 0) {
|
|
cpu_dest = cpu_data;
|
|
oldc = cpu_state.flags & C_FLAG;
|
|
if (is_nec && ((rmdat & 0x38) == 0x30))
|
|
rmdat &= 0xef; /* Make it 0x20, so it aliases to SHL. */
|
|
switch (rmdat & 0x38) {
|
|
case 0x00: /* ROL */
|
|
set_cf(top_bit(cpu_data, bits));
|
|
cpu_data <<= 1;
|
|
cpu_data |= ((cpu_state.flags & C_FLAG) ? 1 : 0);
|
|
set_of_rotate(bits);
|
|
set_af(0);
|
|
break;
|
|
case 0x08: /* ROR */
|
|
set_cf((cpu_data & 1) != 0);
|
|
cpu_data >>= 1;
|
|
if (cpu_state.flags & C_FLAG)
|
|
cpu_data |= (!(opcode & 1) ? 0x80 : 0x8000);
|
|
set_of_rotate(bits);
|
|
set_af(0);
|
|
break;
|
|
case 0x10: /* RCL */
|
|
set_cf(top_bit(cpu_data, bits));
|
|
cpu_data = (cpu_data << 1) | (oldc ? 1 : 0);
|
|
set_of_rotate(bits);
|
|
set_af(0);
|
|
break;
|
|
case 0x18: /* RCR */
|
|
set_cf((cpu_data & 1) != 0);
|
|
cpu_data >>= 1;
|
|
if (oldc)
|
|
cpu_data |= (!(opcode & 0x01) ? 0x80 : 0x8000);
|
|
set_cf((cpu_dest & 1) != 0);
|
|
set_of_rotate(bits);
|
|
set_af(0);
|
|
break;
|
|
case 0x20: /* SHL */
|
|
set_cf(top_bit(cpu_data, bits));
|
|
cpu_data <<= 1;
|
|
set_of_rotate(bits);
|
|
set_af((cpu_data & 0x10) != 0);
|
|
set_pzs(bits);
|
|
break;
|
|
case 0x28: /* SHR */
|
|
set_cf((cpu_data & 1) != 0);
|
|
cpu_data >>= 1;
|
|
set_of_rotate(bits);
|
|
set_af(0);
|
|
set_pzs(bits);
|
|
break;
|
|
case 0x30: /* SETMO - undocumented? */
|
|
bitwise(bits, 0xffff);
|
|
set_cf(0);
|
|
set_of_rotate(bits);
|
|
set_af(0);
|
|
set_pzs(bits);
|
|
break;
|
|
case 0x38: /* SAR */
|
|
set_cf((cpu_data & 1) != 0);
|
|
cpu_data >>= 1;
|
|
if (!(opcode & 1))
|
|
cpu_data |= (cpu_dest & 0x80);
|
|
else
|
|
cpu_data |= (cpu_dest & 0x8000);
|
|
set_of_rotate(bits);
|
|
set_af(0);
|
|
set_pzs(bits);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
--cpu_src;
|
|
}
|
|
|
|
if (opcode <= 0xd1) {
|
|
if (cpu_mod != 3)
|
|
do_cycle_i();
|
|
}
|
|
|
|
/* write_operand() */
|
|
set_ea(cpu_data);
|
|
break;
|
|
|
|
case 0xd4: /* AAM */
|
|
/* read_operand8() */
|
|
cpu_src = biu_pfq_fetchb();
|
|
|
|
if (is_nec) {
|
|
if (!cpu_src)
|
|
cpu_src = 10;
|
|
AH = AL / cpu_src;
|
|
AL %= cpu_src;
|
|
cpu_data = AL;
|
|
set_pzs(8);
|
|
do_cycles(12);
|
|
} else {
|
|
/* Confirmed to be identical on V20/V30 to 808x, per
|
|
XTIDE working correctly on both (it uses AAM with
|
|
parameter other than 10. */
|
|
/* aam() */
|
|
if (x86_div(AL, 0)) {
|
|
cpu_data = AL;
|
|
set_pzs(8);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0xd5: /* AAD */
|
|
/* read_operand8() */
|
|
cpu_src = biu_pfq_fetchb();
|
|
|
|
if (is_nec) {
|
|
cpu_src = 10;
|
|
AL = (AH * cpu_src) + AL;
|
|
AH = 0;
|
|
cpu_data = AL;
|
|
set_pzs(8);
|
|
do_cycles(4);
|
|
} else {
|
|
if (is_nec)
|
|
cpu_src = 10;
|
|
/* aad() */
|
|
mul(cpu_src, AH);
|
|
cpu_dest = AL;
|
|
cpu_src = cpu_data;
|
|
add(8);
|
|
AL = cpu_data;
|
|
AH = 0x00;
|
|
set_pzs(8);
|
|
}
|
|
break;
|
|
|
|
case 0xd6: /* SALC */
|
|
if (is_nec) {
|
|
do_cycles(14);
|
|
fallthrough;
|
|
} else {
|
|
AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00;
|
|
break;
|
|
}
|
|
case 0xd7: /* XLAT */
|
|
do_cycles_i(3);
|
|
/* biu_read_u8() */
|
|
cpu_state.eaaddr = (BX + AL) & 0xffff;
|
|
tempb = readmemb((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr);
|
|
/* set_register8() */
|
|
AL = tempb;
|
|
break;
|
|
|
|
case 0xd8 ... 0xdf: /* ESC - FPU instructions. */
|
|
/* read_operand16() */
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2); /* load_operand() */
|
|
tempw = cpu_state.pc;
|
|
geteaw();
|
|
/* fpu_op() */
|
|
if (hasfpu) {
|
|
if (fpu_softfloat) {
|
|
switch (opcode) {
|
|
case 0xd8:
|
|
ops_sf_fpu_8087_d8[(rmdat >> 3) & 0x1f](rmdat);
|
|
break;
|
|
case 0xd9:
|
|
ops_sf_fpu_8087_d9[rmdat & 0xff](rmdat);
|
|
break;
|
|
case 0xda:
|
|
ops_sf_fpu_8087_da[rmdat & 0xff](rmdat);
|
|
break;
|
|
case 0xdb:
|
|
ops_sf_fpu_8087_db[rmdat & 0xff](rmdat);
|
|
break;
|
|
case 0xdc:
|
|
ops_sf_fpu_8087_dc[(rmdat >> 3) & 0x1f](rmdat);
|
|
break;
|
|
case 0xdd:
|
|
ops_sf_fpu_8087_dd[rmdat & 0xff](rmdat);
|
|
break;
|
|
case 0xde:
|
|
ops_sf_fpu_8087_de[rmdat & 0xff](rmdat);
|
|
break;
|
|
case 0xdf:
|
|
ops_sf_fpu_8087_df[rmdat & 0xff](rmdat);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
switch (opcode) {
|
|
case 0xd8:
|
|
ops_fpu_8087_d8[(rmdat >> 3) & 0x1f](rmdat);
|
|
break;
|
|
case 0xd9:
|
|
ops_fpu_8087_d9[rmdat & 0xff](rmdat);
|
|
break;
|
|
case 0xdA:
|
|
ops_fpu_8087_da[rmdat & 0xff](rmdat);
|
|
break;
|
|
case 0xdb:
|
|
ops_fpu_8087_db[rmdat & 0xff](rmdat);
|
|
break;
|
|
case 0xdc:
|
|
ops_fpu_8087_dc[(rmdat >> 3) & 0x1f](rmdat);
|
|
break;
|
|
case 0xdd:
|
|
ops_fpu_8087_dd[rmdat & 0xff](rmdat);
|
|
break;
|
|
case 0xde:
|
|
ops_fpu_8087_de[rmdat & 0xff](rmdat);
|
|
break;
|
|
case 0xdf:
|
|
ops_fpu_8087_df[rmdat & 0xff](rmdat);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
cpu_state.pc = tempw; /* Do this as the x87 code advances it, which is needed on
|
|
the 286+ core, but not here. */
|
|
break;
|
|
|
|
case 0xe0: /* LOOPNE & LOOPE */
|
|
case 0xe1:
|
|
/* decrement_register16() */
|
|
--CX;
|
|
do_cycles_i(2);
|
|
|
|
zero_cond = !(cpu_state.flags & Z_FLAG);
|
|
if (opcode == 0xe1)
|
|
zero_cond = !zero_cond;
|
|
|
|
/* read_operand8() */
|
|
cpu_data = biu_pfq_fetchb();
|
|
|
|
if ((CX != 0x0000) && zero_cond) {
|
|
rel8 = (int8_t) cpu_data;
|
|
new_ip = (cpu_state.pc + rel8) & 0xffff;
|
|
reljmp(new_ip, 1);
|
|
jump = 1;
|
|
do_print = 0;
|
|
} else {
|
|
do_cycle_i();
|
|
do_print = 1;
|
|
}
|
|
break;
|
|
|
|
case 0xe2: /* LOOP */
|
|
/* decrement_register16() */
|
|
--CX;
|
|
do_cycles_i(2);
|
|
|
|
/* read_operand8() */
|
|
cpu_data = biu_pfq_fetchb();
|
|
|
|
if (CX != 0x0000) {
|
|
rel8 = (int8_t) cpu_data;
|
|
new_ip = (cpu_state.pc + rel8) & 0xffff;
|
|
reljmp(new_ip, 1);
|
|
jump = 1;
|
|
do_print = 0;
|
|
}
|
|
if (!jump) {
|
|
do_cycle();
|
|
do_print = 1;
|
|
}
|
|
break;
|
|
|
|
case 0xe3: /* JCXZ */
|
|
do_cycles_i(2);
|
|
/* read_operand8() */
|
|
cpu_data = biu_pfq_fetchb();
|
|
|
|
do_cycle_i();
|
|
|
|
if (CX == 0x0000) {
|
|
rel8 = (int8_t) cpu_data;
|
|
new_ip = (cpu_state.pc + rel8) & 0xffff;
|
|
reljmp(new_ip, 1);
|
|
jump = 1;
|
|
} else
|
|
do_cycle_i();
|
|
break;
|
|
|
|
case 0xe4: /* IN al, imm8 */
|
|
bits = 8;
|
|
/* read_operand8() */
|
|
cpu_data = biu_pfq_fetchb();
|
|
do_cycles_i(2);
|
|
|
|
/* biu_io_read_u8() */
|
|
cpu_state.eaaddr = cpu_data;
|
|
cpu_io_vx0(bits, 0, cpu_state.eaaddr);
|
|
/* set_register8() */
|
|
break;
|
|
|
|
case 0xe5: /* IN ax, imm8 */
|
|
bits = 16;
|
|
/* read_operand16() */
|
|
cpu_data = biu_pfq_fetchb();
|
|
do_cycles_i(2);
|
|
|
|
/* biu_io_read_u16() */
|
|
cpu_state.eaaddr = cpu_data;
|
|
cpu_io_vx0(bits, 0, cpu_state.eaaddr);
|
|
/* set_register16() */
|
|
break;
|
|
|
|
case 0xe6: /* OUT imm8, al */
|
|
bits = 8;
|
|
/* read_operand8() */
|
|
cpu_data = biu_pfq_fetchb();
|
|
/* read_operand8() */
|
|
tempb = AL;
|
|
do_cycles_i(2);
|
|
|
|
/* biu_io_write_u8() */
|
|
cpu_state.eaaddr = cpu_data;
|
|
cpu_data = tempb;
|
|
cpu_io_vx0(bits, 1, cpu_state.eaaddr);
|
|
break;
|
|
|
|
case 0xe7: /* OUT imm8, ax */
|
|
bits = 16;
|
|
/* read_operand8() */
|
|
cpu_data = biu_pfq_fetchb();
|
|
/* read_operand16() */
|
|
tempw = AX;
|
|
do_cycles_i(2);
|
|
|
|
/* biu_io_write_u16() */
|
|
cpu_state.eaaddr = cpu_data;
|
|
cpu_data = tempw;
|
|
cpu_io_vx0(bits, 1, cpu_state.eaaddr);
|
|
break;
|
|
|
|
case 0xe8: /* CALL rel16 */
|
|
/* read_operand16() */
|
|
rel16 = (int16_t) biu_pfq_fetchw();
|
|
|
|
biu_suspend_fetch();
|
|
do_cycles_i(4);
|
|
|
|
old_ip = cpu_state.pc;
|
|
new_ip = cpu_state.pc + rel16;
|
|
|
|
set_ip(new_ip);
|
|
biu_queue_flush();
|
|
do_cycles_i(3);
|
|
|
|
push(&old_ip);
|
|
jump = 1;
|
|
break;
|
|
|
|
case 0xe9: /* JMP rel16 */
|
|
/* read_operand16() */
|
|
rel16 = (int16_t) biu_pfq_fetchw();
|
|
new_ip = (cpu_state.pc + rel16) & 0xffff;
|
|
|
|
reljmp(new_ip, 1);
|
|
jump = 1;
|
|
break;
|
|
|
|
case 0xea: /* JMP far [addr16:16] */
|
|
/* read_operand_faraddr() */
|
|
addr = biu_pfq_fetchw();
|
|
tempw = biu_pfq_fetchw();
|
|
load_cs(tempw);
|
|
set_ip(addr);
|
|
|
|
biu_suspend_fetch();
|
|
do_cycles_i(2);
|
|
biu_queue_flush();
|
|
do_cycle_i();
|
|
jump = 1;
|
|
break;
|
|
|
|
case 0xeb: /* JMP rel8 */
|
|
/* read_operand8() */
|
|
rel8 = (int8_t) biu_pfq_fetchb();
|
|
new_ip = (cpu_state.pc + rel8) & 0xffff;
|
|
|
|
reljmp(new_ip, 1);
|
|
jump = 1;
|
|
break;
|
|
|
|
case 0xec: /* IN al, dx */
|
|
bits = 8;
|
|
/* read_operand8() */
|
|
cpu_data = DX;
|
|
/* biu_io_read_u8() */
|
|
cpu_state.eaaddr = cpu_data;
|
|
cpu_io_vx0(bits, 0, cpu_state.eaaddr);
|
|
/* set_register8() */
|
|
break;
|
|
|
|
case 0xed: /* IN ax, dx */
|
|
bits = 16;
|
|
/* read_operand16() */
|
|
cpu_data = DX;
|
|
/* biu_io_read_u16() */
|
|
cpu_state.eaaddr = cpu_data;
|
|
cpu_io_vx0(bits, 0, cpu_state.eaaddr);
|
|
/* set_register16() */
|
|
break;
|
|
|
|
case 0xee: /* OUT dx, al */
|
|
bits = 8;
|
|
/* read_operand8() */
|
|
cpu_data = DX;
|
|
/* read_operand8() */
|
|
tempb = AL;
|
|
do_cycle_i();
|
|
|
|
/* biu_io_write_u8() */
|
|
cpu_state.eaaddr = cpu_data;
|
|
cpu_data = tempb;
|
|
cpu_io_vx0(bits, 1, cpu_state.eaaddr);
|
|
break;
|
|
|
|
case 0xef: /* OUT dx, ax */
|
|
bits = 16;
|
|
/* read_operand8() */
|
|
cpu_data = DX;
|
|
/* read_operand16() */
|
|
tempw = AX;
|
|
do_cycle_i();
|
|
|
|
/* biu_io_write_u16() */
|
|
cpu_state.eaaddr = cpu_data;
|
|
cpu_data = tempw;
|
|
cpu_io_vx0(bits, 1, cpu_state.eaaddr);
|
|
break;
|
|
|
|
case 0xf0:
|
|
case 0xf1: /* LOCK - F1 is alias */
|
|
break;
|
|
|
|
case 0xf2: /* REPNE */
|
|
case 0xf3: /* REPE */
|
|
break;
|
|
|
|
case 0xf4: /* HLT */
|
|
if (is_nec)
|
|
in_hlt = 1;
|
|
|
|
if (!repeating) {
|
|
biu_suspend_fetch();
|
|
// biu_queue_flush();
|
|
do_cycles(2);
|
|
/* TODO: biu_halt(); */
|
|
do_cycle();
|
|
}
|
|
|
|
do_cycle_i();
|
|
do_cycle_i();
|
|
do_cycle_i();
|
|
if (irq_pending()) {
|
|
halted = 0;
|
|
check_interrupts();
|
|
} else {
|
|
repeating = 1;
|
|
completed = 0;
|
|
|
|
halted = 1;
|
|
}
|
|
|
|
if (is_nec)
|
|
in_hlt = 0;
|
|
break;
|
|
|
|
case 0xf5: /* CMC */
|
|
cpu_state.flags ^= C_FLAG;
|
|
break;
|
|
|
|
case 0xf6: /* Miscellaneuous Opcode Extensions, r/m8, imm8 */
|
|
bits = 8;
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(is_nec ? 1 : 2); /* load_operand() */
|
|
negate = !!in_rep;
|
|
|
|
if (is_nec && ((rmdat & 0x38) >= 0x20)) switch (rmdat & 0x38) {
|
|
case 0x20: /* MUL */
|
|
/* read_operand8() */
|
|
cpu_data = get_ea();
|
|
|
|
AX = AL * cpu_data;
|
|
if (AH)
|
|
cpu_state.flags |= (C_FLAG | V_FLAG);
|
|
else
|
|
cpu_state.flags &= ~(C_FLAG | V_FLAG);
|
|
|
|
do_cycles((cpu_mod == 3) ? 24 : 30);
|
|
break;
|
|
case 0x28: /* IMUL */
|
|
/* read_operand8() */
|
|
cpu_data = get_ea();
|
|
|
|
tempws = (int) ((int8_t) AL) * (int) ((int8_t) cpu_data);
|
|
AX = tempws & 0xffff;
|
|
if (((int16_t) AX >> 7) != 0 && ((int16_t) AX >> 7) != -1)
|
|
cpu_state.flags |= (C_FLAG | V_FLAG);
|
|
else
|
|
cpu_state.flags &= ~(C_FLAG | V_FLAG);
|
|
|
|
do_cycles((cpu_mod == 3) ? 13 : 19);
|
|
break;
|
|
case 0x30: /* DIV */
|
|
/* read_operand8() */
|
|
cpu_data = get_ea();
|
|
|
|
src16 = AX;
|
|
if (cpu_data)
|
|
tempw = src16 / cpu_data;
|
|
if (cpu_data && !(tempw & 0xff00)) {
|
|
AH = src16 % cpu_data;
|
|
AL = (src16 / cpu_data) & 0xff;
|
|
cpu_state.flags |= 0x8D5;
|
|
cpu_state.flags &= ~1;
|
|
} else {
|
|
intr_routine(0, 0);
|
|
break;
|
|
}
|
|
|
|
do_cycles((cpu_mod == 3) ? 21 : 27);
|
|
break;
|
|
case 0x38: /* IDIV */
|
|
/* read_operand8() */
|
|
cpu_data = get_ea();
|
|
|
|
tempws = (int) (int16_t) AX;
|
|
if (cpu_data != 0)
|
|
tempws2 = tempws / (int) ((int8_t) cpu_data);
|
|
temps = tempws2 & 0xff;
|
|
if (cpu_data && ((int) temps == tempws2)) {
|
|
AH = (tempws % (int) ((int8_t) cpu_data)) & 0xff;
|
|
AL = tempws2 & 0xff;
|
|
cpu_state.flags |= 0x8D5;
|
|
cpu_state.flags &= ~1;
|
|
} else {
|
|
intr_routine(0, 0);
|
|
break;
|
|
}
|
|
|
|
do_cycles((cpu_mod == 3) ? 11 : 17);
|
|
break;
|
|
} else switch (rmdat & 0x38) {
|
|
case 0x00: /* TEST */
|
|
case 0x08:
|
|
/* read_operand8() */
|
|
cpu_data = get_ea();
|
|
/* read_operand8() */
|
|
cpu_src = biu_pfq_fetch();
|
|
|
|
do_cycles_i(is_nec ? 1 : 2);
|
|
|
|
/* math_op8() */
|
|
test(bits, cpu_data, cpu_src);
|
|
break;
|
|
case 0x10: /* NOT */
|
|
case 0x18: /* NEG */
|
|
/* read_operand8() */
|
|
cpu_data = get_ea();
|
|
/* math_op8() */
|
|
if ((rmdat & 0x38) == 0x10)
|
|
cpu_data = ~cpu_data;
|
|
else {
|
|
cpu_src = cpu_data;
|
|
cpu_dest = 0;
|
|
sub(bits);
|
|
}
|
|
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2);
|
|
|
|
/* write_operand8() */
|
|
set_ea(cpu_data);
|
|
break;
|
|
|
|
case 0x20: /* MUL */
|
|
case 0x28: /* IMUL */
|
|
/* read_operand8() */
|
|
cpu_data = get_ea();
|
|
|
|
/* mul8() */
|
|
old_flags = cpu_state.flags;
|
|
mul(get_accum(bits), cpu_data);
|
|
prod16 = ((cpu_dest & 0xff) << 8) | (cpu_data & 0xff);
|
|
if (negate)
|
|
prod16 = -prod16;
|
|
cpu_dest = prod16 >> 8;
|
|
cpu_data = prod16 & 0xff;
|
|
AL = (uint8_t) cpu_data;
|
|
AH = (uint8_t) cpu_dest;
|
|
set_co_mul(bits, AH != ((AL & 0x80) == 0 ||
|
|
(rmdat & 0x38) == 0x20 ? 0 : 0xff));
|
|
if (!is_nec)
|
|
cpu_data = AH;
|
|
set_sf(bits);
|
|
set_pf();
|
|
/* NOTE: When implementing the V20, care should be taken to not change
|
|
the zero flag. */
|
|
if (is_nec)
|
|
cpu_state.flags = (cpu_state.flags & ~Z_FLAG) | (old_flags & Z_FLAG);
|
|
break;
|
|
|
|
case 0x30: /* DIV */
|
|
case 0x38: /* IDIV */
|
|
/* read_operand8() */
|
|
cpu_data = get_ea();
|
|
|
|
cpu_src = cpu_data;
|
|
if (x86_div(AL, AH)) {
|
|
if (!is_nec && negate)
|
|
AL = -AL;
|
|
do_cycle();
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 0xf7: /* Miscellaneuous Opcode Extensions, r/m16, imm16 */
|
|
bits = 16;
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(is_nec ? 1 : 2); /* load_operand() */
|
|
negate = !!in_rep;
|
|
|
|
if (is_nec && ((rmdat & 0x38) >= 0x20)) switch (rmdat & 0x38) {
|
|
case 0x20: /* MUL */
|
|
/* read_operand16() */
|
|
cpu_data = get_ea();
|
|
|
|
templ = AX * cpu_data;
|
|
AX = templ & 0xFFFF;
|
|
DX = templ >> 16;
|
|
if (DX)
|
|
cpu_state.flags |= (C_FLAG | V_FLAG);
|
|
else
|
|
cpu_state.flags &= ~(C_FLAG | V_FLAG);
|
|
|
|
do_cycles((cpu_mod == 3) ? 29 : 35);
|
|
break;
|
|
case 0x28: /* IMUL */
|
|
/* read_operand16() */
|
|
cpu_data = get_ea();
|
|
|
|
templ = (int) ((int16_t) AX) * (int) ((int16_t) cpu_data);
|
|
AX = templ & 0xFFFF;
|
|
DX = templ >> 16;
|
|
if (((int32_t) templ >> 15) != 0 && ((int32_t) templ >> 15) != -1)
|
|
cpu_state.flags |= (C_FLAG | V_FLAG);
|
|
else
|
|
cpu_state.flags &= ~(C_FLAG | V_FLAG);
|
|
|
|
do_cycles((cpu_mod == 3) ? 17 : 27);
|
|
break;
|
|
case 0x30: /* DIV */
|
|
/* read_operand16() */
|
|
cpu_data = get_ea();
|
|
|
|
templ = (DX << 16) | AX;
|
|
if (cpu_data)
|
|
templ2 = templ / cpu_data;
|
|
if (cpu_data && !(templ2 & 0xffff0000)) {
|
|
DX = templ % cpu_data;
|
|
AX = (templ / cpu_data) & 0xffff;
|
|
cpu_data = AX;
|
|
set_pzs(16);
|
|
} else {
|
|
intr_routine(0, 0);
|
|
break;
|
|
}
|
|
|
|
do_cycles((cpu_mod == 3) ? 26 : 36);
|
|
break;
|
|
case 0x38: /* IDIV */
|
|
/* read_operand16() */
|
|
cpu_data = get_ea();
|
|
|
|
tempws = (int) ((DX << 16) | AX);
|
|
if (cpu_data)
|
|
tempws2 = tempws / (int) ((int16_t) cpu_data);
|
|
temps16 = tempws2 & 0xffff;
|
|
if ((cpu_data != 0) && ((int) temps16 == tempws2)) {
|
|
DX = tempws % (int) ((int16_t) cpu_data);
|
|
AX = tempws2 & 0xffff;
|
|
cpu_data = AX;
|
|
set_pzs(16);
|
|
} else {
|
|
intr_routine(0, 0);
|
|
break;
|
|
}
|
|
|
|
do_cycles((cpu_mod == 3) ? 13 : 23);
|
|
break;
|
|
} else switch (rmdat & 0x38) {
|
|
case 0x00: /* TEST */
|
|
case 0x08:
|
|
/* read_operand16() */
|
|
cpu_data = get_ea();
|
|
/* read_operand16() */
|
|
cpu_src = biu_pfq_fetch();
|
|
|
|
do_cycle_i();
|
|
|
|
/* math_op16() */
|
|
test(bits, cpu_data, cpu_src);
|
|
break;
|
|
case 0x10: /* NOT */
|
|
case 0x18: /* NEG */
|
|
/* read_operand16() */
|
|
cpu_data = get_ea();
|
|
/* math_op16() */
|
|
if ((rmdat & 0x38) == 0x10)
|
|
cpu_data = ~cpu_data;
|
|
else {
|
|
cpu_src = cpu_data;
|
|
cpu_dest = 0;
|
|
sub(bits);
|
|
}
|
|
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2);
|
|
|
|
/* write_operand16() */
|
|
set_ea(cpu_data);
|
|
break;
|
|
|
|
case 0x20: /* MUL */
|
|
case 0x28: /* IMUL */
|
|
/* read_operand16() */
|
|
cpu_data = get_ea();
|
|
|
|
/* mul8() */
|
|
old_flags = cpu_state.flags;
|
|
mul(get_accum(bits), cpu_data);
|
|
prod32 = (((uint32_t) cpu_dest) << 16) | cpu_data;
|
|
if (negate)
|
|
prod32 = -prod32;
|
|
cpu_dest = prod32 >> 16;
|
|
cpu_data = prod32 & 0xffff;
|
|
AX = cpu_data;
|
|
DX = cpu_dest;
|
|
set_co_mul(bits, DX != ((AX & 0x8000) == 0 ||
|
|
(rmdat & 0x38) == 0x20 ? 0 : 0xffff));
|
|
cpu_data = DX;
|
|
set_sf(bits);
|
|
set_pf();
|
|
/* NOTE: When implementing the V20, care should be taken to not change
|
|
the zero flag. */
|
|
if (is_nec)
|
|
cpu_state.flags = (cpu_state.flags & ~Z_FLAG) | (old_flags & Z_FLAG);
|
|
break;
|
|
|
|
case 0x30: /* DIV */
|
|
case 0x38: /* IDIV */
|
|
/* read_operand16() */
|
|
cpu_data = get_ea();
|
|
|
|
cpu_src = cpu_data;
|
|
if (x86_div(AX, DX)) {
|
|
if (!is_nec && negate)
|
|
AX = -AX;
|
|
do_cycle();
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 0xf8: /* CLCSTC */
|
|
case 0xf9:
|
|
set_cf(opcode & 1);
|
|
break;
|
|
|
|
case 0xfa: /* CLISTI */
|
|
case 0xfb:
|
|
set_if(opcode & 1);
|
|
break;
|
|
|
|
case 0xfc: /* CLDSTD */
|
|
case 0xfd:
|
|
set_df(opcode & 1);
|
|
break;
|
|
|
|
case 0xfe:
|
|
bits = 8;
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(is_nec ? 1 : 2); /* load_operand() */
|
|
read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits);
|
|
switch (rmdat & 0x38) {
|
|
case 0x00: /* INC rm */
|
|
case 0x08: /* DEC rm */
|
|
/* read_operand8() */
|
|
/* math_op8() */
|
|
cpu_dest = cpu_data;
|
|
cpu_src = 1;
|
|
if ((rmdat & 0x38) == 0x00) {
|
|
cpu_data = cpu_dest + cpu_src;
|
|
set_of_add(bits);
|
|
} else {
|
|
cpu_data = cpu_dest - cpu_src;
|
|
set_of_sub(bits);
|
|
}
|
|
do_af();
|
|
set_pzs(bits);
|
|
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2);
|
|
/* write_operand8() */
|
|
set_ea(cpu_data);
|
|
break;
|
|
case 0x10: /* CALL rm */
|
|
/* read_operand8() */
|
|
cpu_data_opff_rm();
|
|
|
|
cpu_state.oldpc = cpu_state.pc;
|
|
push((uint16_t *) &(cpu_state.oldpc));
|
|
|
|
biu_suspend_fetch();
|
|
do_cycles(4);
|
|
biu_queue_flush();
|
|
|
|
set_ip(cpu_data | 0xff00);
|
|
break;
|
|
case 0x18: /* CALL rmd */
|
|
if (cpu_mod == 3) {
|
|
/* biu_read_u8() */
|
|
cpu_state.eaaddr = 0x0004;
|
|
tempb = readmemb((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr);
|
|
|
|
old_cs = CS & 0x00ff;
|
|
push(&old_cs);
|
|
old_ip = cpu_state.pc & 0x00ff;
|
|
push(&old_ip);
|
|
|
|
biu_suspend_fetch();
|
|
do_cycles(4);
|
|
biu_queue_flush();
|
|
|
|
read_ea_8to16();
|
|
set_ip(cpu_data);
|
|
} else {
|
|
/* read_operand8() */
|
|
new_ip = cpu_data | 0xff00;
|
|
|
|
do_cycles_i(3);
|
|
|
|
/* biu_read_u8() */
|
|
read_ea2(bits);
|
|
cpu_data |= 0xff00;
|
|
new_cs = cpu_data;
|
|
|
|
do_cycle_i();
|
|
biu_suspend_fetch();
|
|
do_cycles_i(3);
|
|
|
|
old_cs = CS & 0x00ff;
|
|
push(&old_cs);
|
|
old_ip = cpu_state.pc & 0x00ff;
|
|
|
|
load_cs(new_cs);
|
|
set_ip(new_ip);
|
|
|
|
do_cycles_i(3);
|
|
biu_queue_flush();
|
|
do_cycles_i(3);
|
|
|
|
push(&old_ip);
|
|
}
|
|
break;
|
|
case 0x20: /* JMP rm */
|
|
/* read_operand8() */
|
|
cpu_data_opff_rm();
|
|
|
|
set_ip(cpu_data | 0xff00);
|
|
|
|
biu_suspend_fetch();
|
|
do_cycles(4);
|
|
biu_queue_flush();
|
|
break;
|
|
case 0x28: /* JMP rmd */
|
|
if (cpu_mod == 3) {
|
|
/* biu_read_u8() */
|
|
cpu_state.eaaddr = 0x0004;
|
|
tempb = readmemb((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr);
|
|
|
|
biu_suspend_fetch();
|
|
do_cycles(4);
|
|
biu_queue_flush();
|
|
|
|
read_ea_8to16();
|
|
set_ip(cpu_data);
|
|
} else {
|
|
/* read_operand8() */
|
|
new_ip = cpu_data | 0xff00;
|
|
|
|
/* biu_read_u8() */
|
|
read_ea2(bits);
|
|
cpu_data |= 0xff00;
|
|
new_cs = cpu_data;
|
|
|
|
biu_suspend_fetch();
|
|
do_cycles(4);
|
|
biu_queue_flush();
|
|
|
|
load_cs(new_cs);
|
|
set_ip(new_ip);
|
|
}
|
|
break;
|
|
case 0x30: /* PUSH rm */
|
|
case 0x38:
|
|
/* read_operand8() */
|
|
do_cycles_i(3);
|
|
cpu_data &= 0x00ff;
|
|
push((uint16_t *) &cpu_data);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 0xff:
|
|
bits = 16;
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(is_nec ? 1 : 2); /* load_operand() */
|
|
read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits);
|
|
switch (rmdat & 0x38) {
|
|
case 0x00: /* INC rm */
|
|
case 0x08: /* DEC rm */
|
|
/* read_operand16() */
|
|
/* math_op16() */
|
|
cpu_dest = cpu_data;
|
|
cpu_src = 1;
|
|
if ((rmdat & 0x38) == 0x00) {
|
|
cpu_data = cpu_dest + cpu_src;
|
|
set_of_add(bits);
|
|
} else {
|
|
cpu_data = cpu_dest - cpu_src;
|
|
set_of_sub(bits);
|
|
}
|
|
do_af();
|
|
set_pzs(bits);
|
|
if (cpu_mod != 3)
|
|
do_cycles_i(2);
|
|
/* write_operand16() */
|
|
set_ea(cpu_data);
|
|
break;
|
|
case 0x10: /* CALL rm */
|
|
/* read_operand16() */
|
|
cpu_data_opff_rm();
|
|
|
|
biu_suspend_fetch();
|
|
do_cycles(4);
|
|
|
|
cpu_state.oldpc = cpu_state.pc;
|
|
|
|
old_ip = cpu_state.pc;
|
|
set_ip(cpu_data);
|
|
biu_queue_flush();
|
|
do_cycles_i(3);
|
|
|
|
push(&old_ip);
|
|
break;
|
|
case 0x18: /* CALL rmd */
|
|
if (cpu_mod == 3) {
|
|
new_ip = cpu_data;
|
|
|
|
/* biu_read_u16() */
|
|
cpu_state.eaaddr = 0x0004;
|
|
new_cs = readmemw((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr);
|
|
|
|
do_cycle_i();
|
|
biu_suspend_fetch();
|
|
do_cycles_i(3);
|
|
|
|
push(&CS);
|
|
old_ip = cpu_state.pc;
|
|
set_ip(new_ip);
|
|
|
|
load_cs(new_cs);
|
|
|
|
do_cycles_i(3);
|
|
biu_queue_flush();
|
|
do_cycles_i(3);
|
|
|
|
push(&old_ip);
|
|
} else {
|
|
do_cycle_i();
|
|
/* read_operand_farptr() */
|
|
new_ip = cpu_data;
|
|
read_ea2(bits);
|
|
new_cs = cpu_data;
|
|
|
|
do_cycle_i();
|
|
|
|
biu_suspend_fetch();
|
|
do_cycles_i(3);
|
|
|
|
push(&CS);
|
|
|
|
load_cs(new_cs);
|
|
old_ip = cpu_state.pc;
|
|
set_ip(new_ip);
|
|
do_cycles_i(3);
|
|
biu_queue_flush();
|
|
do_cycles_i(3);
|
|
push(&old_ip);
|
|
}
|
|
break;
|
|
case 0x20: /* JMP rm */
|
|
/* read_operand16() */
|
|
cpu_data_opff_rm();
|
|
|
|
biu_suspend_fetch();
|
|
do_cycle_i();
|
|
set_ip(cpu_data);
|
|
biu_queue_flush();
|
|
break;
|
|
case 0x28: /* JMP rmd */
|
|
if (cpu_mod == 3) {
|
|
new_ip = cpu_data;
|
|
|
|
do_cycle();
|
|
biu_suspend_fetch();
|
|
do_cycle();
|
|
|
|
/* biu_read_u16() */
|
|
cpu_state.eaaddr = 0x0004;
|
|
new_cs = readmemw((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr);
|
|
|
|
push(&CS);
|
|
biu_queue_flush();
|
|
} else {
|
|
do_cycle_i();
|
|
biu_suspend_fetch();
|
|
do_cycle_i();
|
|
|
|
/* read_operand_farptr() */
|
|
new_ip = cpu_data;
|
|
read_ea2(bits);
|
|
new_cs = cpu_data;
|
|
|
|
load_cs(new_cs);
|
|
set_ip(new_ip);
|
|
biu_queue_flush();
|
|
}
|
|
break;
|
|
case 0x30: /* PUSH rm */
|
|
case 0x38:
|
|
/* read_operand16() */
|
|
do_cycles_i(3);
|
|
|
|
if (cpu_rm == 4)
|
|
cpu_rm -= 2;
|
|
push((uint16_t *) &cpu_data);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
x808x_log("Illegal opcode: %02X\n", opcode);
|
|
biu_pfq_fetchb();
|
|
do_cycles(8);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Executes instructions up to the specified number of cycles. */
|
|
void
|
|
execvx0(int cycs)
|
|
{
|
|
cycles += cycs;
|
|
|
|
while (cycles > 0) {
|
|
if (started) {
|
|
started = 0;
|
|
startx86();
|
|
}
|
|
|
|
if (!repeating) {
|
|
cpu_state.oldpc = cpu_state.pc;
|
|
|
|
if (clear_lock) {
|
|
in_lock = 0;
|
|
clear_lock = 0;
|
|
}
|
|
|
|
if (!is_nec || (cpu_state.flags & MD_FLAG))
|
|
decode();
|
|
|
|
oldc = cpu_state.flags & C_FLAG;
|
|
}
|
|
|
|
x808x_log("[%04X:%04X] Opcode: %02X\n", CS, cpu_state.pc, opcode);
|
|
|
|
execute_instruction();
|
|
|
|
if (completed) {
|
|
if (opcode != 0xf4)
|
|
finalize();
|
|
|
|
check_interrupts();
|
|
|
|
if (noint)
|
|
noint = 0;
|
|
}
|
|
|
|
#ifdef USE_GDBSTUB
|
|
if (gdbstub_instruction())
|
|
return;
|
|
#endif
|
|
}
|
|
}
|