4253 lines
65 KiB
C
4253 lines
65 KiB
C
/******************************************************************************
|
|
* NewOswan
|
|
* nec.c:
|
|
* Based on the original Oswan-unix
|
|
* Copyright (c) 2014-2021 986-Studio. All rights reserved.
|
|
*
|
|
******************************************************************************/
|
|
|
|
/****************************************************************************
|
|
|
|
NEC V30MZ(V20/V30/V33) emulator
|
|
|
|
Small changes made by toshi (Cycle count macros changed , "THROUGH" macro added)
|
|
|
|
Small changes made by dox@space.pl (Corrected bug in NEG instruction , different AUX flag handling in some opcodes)
|
|
|
|
(Re)Written June-September 2000 by Bryan McPhail (mish@tendril.co.uk) based
|
|
on code by Oliver Bergmann (Raul_Bloodworth@hotmail.com) who based code
|
|
on the i286 emulator by Fabrice Frances which had initial work based on
|
|
David Hedley's pcemu(!).
|
|
|
|
This new core features 99% accurate cycle counts for each processor,
|
|
there are still some complex situations where cycle counts are wrong,
|
|
typically where a few instructions have differing counts for odd/even
|
|
source and odd/even destination memory operands.
|
|
|
|
Flag settings are also correct for the NEC processors rather than the
|
|
I86 versions.
|
|
|
|
Nb: This emulation should be faster than previous NEC cores, but
|
|
because the old cycle count values were far too high in many cases
|
|
the processor has to do more 'work' than before, so the overall effect
|
|
may be a slower core.
|
|
|
|
****************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
|
|
#include <log.h>
|
|
|
|
#include "nec.h"
|
|
#include "necintrf.h"
|
|
#include "nec_debugger.h"
|
|
|
|
/***************************************************************************/
|
|
/* cpu state */
|
|
/***************************************************************************/
|
|
|
|
uint64_t nec_monotonicCycles;
|
|
int nec_ICount;
|
|
|
|
nec_Regs I;
|
|
|
|
static uint32_t cpu_type;
|
|
static uint32_t prefix_base; /* base address of the latest prefix segment */
|
|
bool seg_prefix; /* prefix segment indicator */
|
|
|
|
|
|
/* The interrupt number of a pending external interrupt pending NMI is 2. */
|
|
/* For INTR interrupts, the level is caught on the bus during an INTA cycle */
|
|
|
|
#include "necinstr.h"
|
|
#include "necea.h"
|
|
#include "necmodrm.h"
|
|
|
|
static int no_interrupt;
|
|
|
|
static uint8_t parity_table[256];
|
|
|
|
/***************************************************************************/
|
|
|
|
void nec_reset(void *param)
|
|
{
|
|
unsigned int i, j, c;
|
|
BREGS reg_name[8] = {AL, CL, DL, BL, AH, CH, DH, BH};
|
|
|
|
nec_monotonicCycles = 0;
|
|
|
|
memset(&I, 0, sizeof(I));
|
|
|
|
no_interrupt = 0;
|
|
I.sregs[CS] = 0xffff;
|
|
|
|
|
|
for (i = 0 ; i < 256 ; i++)
|
|
{
|
|
for (j = i, c = 0 ; j > 0 ; j >>= 1)
|
|
{
|
|
if (j & 1)
|
|
{
|
|
c++;
|
|
}
|
|
}
|
|
|
|
parity_table[i] = !(c & 1);
|
|
}
|
|
|
|
I.ZeroVal = I.ParityVal = 1;
|
|
SetMD(1); /* set the mode-flag = native mode */
|
|
|
|
for (i = 0 ; i < 256 ; i++)
|
|
{
|
|
Mod_RM.reg.b[i] = reg_name[(i & 0x38) >> 3];
|
|
Mod_RM.reg.w[i] = (WREGS)((i & 0x38) >> 3);
|
|
}
|
|
|
|
for (i = 0xc0 ; i < 0x100 ; i++)
|
|
{
|
|
Mod_RM.RM.w[i] = (WREGS)(i & 7);
|
|
Mod_RM.RM.b[i] = (BREGS)reg_name[i & 7];
|
|
}
|
|
}
|
|
|
|
void nec_exit(void)
|
|
{
|
|
|
|
}
|
|
|
|
void dump_memory();
|
|
|
|
|
|
void nec_int(uint16_t vector)
|
|
{
|
|
uint32_t dest_seg, dest_off;
|
|
|
|
if (I.IF)
|
|
{
|
|
i_pushf();
|
|
I.TF = I.IF = 0;
|
|
dest_off = ReadWord(vector);
|
|
dest_seg = ReadWord(vector + 2);
|
|
|
|
if ((dest_off == 0) && (dest_seg == 0))
|
|
{
|
|
Log(TLOG_PANIC, "NEC v30", "Something wrong with the interrupt, exiting...");
|
|
//dump_memory();
|
|
return;
|
|
}
|
|
|
|
PUSH(I.sregs[CS]);
|
|
PUSH(I.ip);
|
|
I.ip = (int16_t)dest_off;
|
|
I.sregs[CS] = (int16_t)dest_seg;
|
|
}
|
|
}
|
|
|
|
static void nec_interrupt(uint32_t int_num, /*BOOLEAN*/ int md_flag)
|
|
{
|
|
uint32_t dest_seg, dest_off;
|
|
|
|
if (int_num == UINT32_MAX)
|
|
{
|
|
return;
|
|
}
|
|
|
|
i_pushf();
|
|
I.TF = I.IF = 0;
|
|
|
|
|
|
dest_off = ReadWord((int_num) * 4);
|
|
dest_seg = ReadWord((int_num) * 4 + 2);
|
|
|
|
if ((dest_off == 0) && (dest_seg == 0))
|
|
{
|
|
Log(TLOG_PANIC, "NEC v30", "Something wrong with the interrupt, exiting...");
|
|
//dump_memory();
|
|
return;
|
|
}
|
|
|
|
|
|
PUSH(I.sregs[CS]);
|
|
PUSH(I.ip);
|
|
I.ip = (int16_t)dest_off;
|
|
I.sregs[CS] = (int16_t)dest_seg;
|
|
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* OPCODES */
|
|
/****************************************************************************/
|
|
|
|
#define OP(num, func_name) static void func_name(void)
|
|
|
|
|
|
OP(0x00, i_add_br8)
|
|
{
|
|
DEF_br8;
|
|
ADDB;
|
|
PutbackRMByte(ModRM, dst);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x01, i_add_wr16)
|
|
{
|
|
DEF_wr16;
|
|
ADDW;
|
|
PutbackRMWord(ModRM, dst);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x02, i_add_r8b)
|
|
{
|
|
DEF_r8b;
|
|
ADDB;
|
|
RegByte(ModRM) = dst;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x03, i_add_r16w)
|
|
{
|
|
DEF_r16w;
|
|
ADDW;
|
|
RegWord(ModRM) = dst;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x04, i_add_ald8)
|
|
{
|
|
DEF_ald8;
|
|
ADDB;
|
|
I.regs.b[AL] = dst;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x05, i_add_axd16)
|
|
{
|
|
DEF_axd16;
|
|
ADDW;
|
|
I.regs.w[AW] = dst;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x06, i_push_es)
|
|
{
|
|
PUSH(I.sregs[ES]);
|
|
CLK(2);
|
|
}
|
|
|
|
OP(0x07, i_pop_es)
|
|
{
|
|
POP(I.sregs[ES]);
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0x08, i_or_br8)
|
|
{
|
|
DEF_br8;
|
|
ORB;
|
|
PutbackRMByte(ModRM, dst);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x09, i_or_wr16)
|
|
{
|
|
DEF_wr16;
|
|
ORW;
|
|
PutbackRMWord(ModRM, dst);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x0a, i_or_r8b)
|
|
{
|
|
DEF_r8b;
|
|
ORB;
|
|
RegByte(ModRM) = dst;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x0b, i_or_r16w)
|
|
{
|
|
DEF_r16w;
|
|
ORW;
|
|
RegWord(ModRM) = dst;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x0c, i_or_ald8)
|
|
{
|
|
DEF_ald8;
|
|
ORB;
|
|
I.regs.b[AL] = dst;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x0d, i_or_axd16)
|
|
{
|
|
DEF_axd16;
|
|
ORW;
|
|
I.regs.w[AW] = dst;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x0e, i_push_cs)
|
|
{
|
|
PUSH(I.sregs[CS]);
|
|
CLK(2);
|
|
}
|
|
|
|
OP(0x0f, i_pre_nec)
|
|
{
|
|
uint32_t ModRM, tmp, tmp2; /* pop cs at V30MZ? */
|
|
|
|
switch (FETCH)
|
|
{
|
|
case 0x10 :
|
|
BITOP_BYTE;
|
|
CLKS(3, 3, 4);
|
|
tmp2 = I.regs.b[CL] & 0x7;
|
|
I.ZeroVal = (tmp & (1 << tmp2)) ? 1 : 0;
|
|
I.CarryVal = I.OverVal = 0;
|
|
break; /* Test */
|
|
|
|
case 0x11 :
|
|
BITOP_WORD;
|
|
CLKS(3, 3, 4);
|
|
tmp2 = I.regs.b[CL] & 0xf;
|
|
I.ZeroVal = (tmp & (1 << tmp2)) ? 1 : 0;
|
|
I.CarryVal = I.OverVal = 0;
|
|
break; /* Test */
|
|
|
|
case 0x12 :
|
|
BITOP_BYTE;
|
|
CLKS(5, 5, 4);
|
|
tmp2 = I.regs.b[CL] & 0x7;
|
|
tmp &= ~(1 << tmp2);
|
|
PutbackRMByte(ModRM, tmp);
|
|
break; /* Clr */
|
|
|
|
case 0x13 :
|
|
BITOP_WORD;
|
|
CLKS(5, 5, 4);
|
|
tmp2 = I.regs.b[CL] & 0xf;
|
|
tmp &= ~(1 << tmp2);
|
|
PutbackRMWord(ModRM, tmp);
|
|
break; /* Clr */
|
|
|
|
case 0x14 :
|
|
BITOP_BYTE;
|
|
CLKS(4, 4, 4);
|
|
tmp2 = I.regs.b[CL] & 0x7;
|
|
tmp |= (1 << tmp2);
|
|
PutbackRMByte(ModRM, tmp);
|
|
break; /* Set */
|
|
|
|
case 0x15 :
|
|
BITOP_WORD;
|
|
CLKS(4, 4, 4);
|
|
tmp2 = I.regs.b[CL] & 0xf;
|
|
tmp |= (1 << tmp2);
|
|
PutbackRMWord(ModRM, tmp);
|
|
break; /* Set */
|
|
|
|
case 0x16 :
|
|
BITOP_BYTE;
|
|
CLKS(4, 4, 4);
|
|
tmp2 = I.regs.b[CL] & 0x7;
|
|
BIT_NOT;
|
|
PutbackRMByte(ModRM, tmp);
|
|
break; /* Not */
|
|
|
|
case 0x17 :
|
|
BITOP_WORD;
|
|
CLKS(4, 4, 4);
|
|
tmp2 = I.regs.b[CL] & 0xf;
|
|
BIT_NOT;
|
|
PutbackRMWord(ModRM, tmp);
|
|
break; /* Not */
|
|
|
|
case 0x18 :
|
|
BITOP_BYTE;
|
|
CLKS(4, 4, 4);
|
|
tmp2 = (FETCH) & 0x7;
|
|
I.ZeroVal = (tmp & (1 << tmp2)) ? 1 : 0;
|
|
I.CarryVal = I.OverVal = 0;
|
|
break; /* Test */
|
|
|
|
case 0x19 :
|
|
BITOP_WORD;
|
|
CLKS(4, 4, 4);
|
|
tmp2 = (FETCH) & 0xf;
|
|
I.ZeroVal = (tmp & (1 << tmp2)) ? 1 : 0;
|
|
I.CarryVal = I.OverVal = 0;
|
|
break; /* Test */
|
|
|
|
case 0x1a :
|
|
BITOP_BYTE;
|
|
CLKS(6, 6, 4);
|
|
tmp2 = (FETCH) & 0x7;
|
|
tmp &= ~(1 << tmp2);
|
|
PutbackRMByte(ModRM, tmp);
|
|
break; /* Clr */
|
|
|
|
case 0x1b :
|
|
BITOP_WORD;
|
|
CLKS(6, 6, 4);
|
|
tmp2 = (FETCH) & 0xf;
|
|
tmp &= ~(1 << tmp2);
|
|
PutbackRMWord(ModRM, tmp);
|
|
break; /* Clr */
|
|
|
|
case 0x1c :
|
|
BITOP_BYTE;
|
|
CLKS(5, 5, 4);
|
|
tmp2 = (FETCH) & 0x7;
|
|
tmp |= (1 << tmp2);
|
|
PutbackRMByte(ModRM, tmp);
|
|
break; /* Set */
|
|
|
|
case 0x1d :
|
|
BITOP_WORD;
|
|
CLKS(5, 5, 4);
|
|
tmp2 = (FETCH) & 0xf;
|
|
tmp |= (1 << tmp2);
|
|
PutbackRMWord(ModRM, tmp);
|
|
break; /* Set */
|
|
|
|
case 0x1e :
|
|
BITOP_BYTE;
|
|
CLKS(5, 5, 4);
|
|
tmp2 = (FETCH) & 0x7;
|
|
BIT_NOT;
|
|
PutbackRMByte(ModRM, tmp);
|
|
break; /* Not */
|
|
|
|
case 0x1f :
|
|
BITOP_WORD;
|
|
CLKS(5, 5, 4);
|
|
tmp2 = (FETCH) & 0xf;
|
|
BIT_NOT;
|
|
PutbackRMWord(ModRM, tmp);
|
|
break; /* Not */
|
|
|
|
case 0x20 :
|
|
ADD4S;
|
|
CLKS(7, 7, 2);
|
|
break;
|
|
|
|
case 0x22 :
|
|
SUB4S;
|
|
CLKS(7, 7, 2);
|
|
break;
|
|
|
|
case 0x26 :
|
|
CMP4S;
|
|
CLKS(7, 7, 2);
|
|
break;
|
|
|
|
case 0x28 :
|
|
ModRM = FETCH;
|
|
tmp = GetRMByte(ModRM);
|
|
tmp <<= 4;
|
|
tmp |= I.regs.b[AL] & 0xf;
|
|
I.regs.b[AL] = (I.regs.b[AL] & 0xf0) | ((tmp >> 8) & 0xf);
|
|
tmp &= 0xff;
|
|
PutbackRMByte(ModRM, tmp);
|
|
CLKM(9, 15);
|
|
break;
|
|
|
|
case 0x2a :
|
|
ModRM = FETCH;
|
|
tmp = GetRMByte(ModRM);
|
|
tmp2 = (I.regs.b[AL] & 0xf) << 4;
|
|
I.regs.b[AL] = (I.regs.b[AL] & 0xf0) | (tmp & 0xf);
|
|
tmp = tmp2 | (tmp >> 4);
|
|
PutbackRMByte(ModRM, tmp);
|
|
CLKM(13, 19);
|
|
break;
|
|
|
|
case 0x31 :
|
|
ModRM = FETCH;
|
|
ModRM = 0;
|
|
break;
|
|
|
|
case 0x33 :
|
|
ModRM = FETCH;
|
|
ModRM = 0;
|
|
break;
|
|
|
|
case 0x92 :
|
|
CLK(2);
|
|
break; /* V25/35 FINT */
|
|
|
|
case 0xe0 :
|
|
ModRM = FETCH;
|
|
ModRM = 0;
|
|
break;
|
|
|
|
case 0xf0 :
|
|
ModRM = FETCH;
|
|
ModRM = 0;
|
|
break;
|
|
|
|
case 0xff :
|
|
ModRM = FETCH;
|
|
ModRM = 0;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
OP(0x10, i_adc_br8)
|
|
{
|
|
DEF_br8;
|
|
src += CF;
|
|
ADDB;
|
|
PutbackRMByte(ModRM, dst);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x11, i_adc_wr16)
|
|
{
|
|
DEF_wr16;
|
|
src += CF;
|
|
ADDW;
|
|
PutbackRMWord(ModRM, dst);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x12, i_adc_r8b)
|
|
{
|
|
DEF_r8b;
|
|
src += CF;
|
|
ADDB;
|
|
RegByte(ModRM) = dst;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x13, i_adc_r16w)
|
|
{
|
|
DEF_r16w;
|
|
src += CF;
|
|
ADDW;
|
|
RegWord(ModRM) = dst;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x14, i_adc_ald8)
|
|
{
|
|
DEF_ald8;
|
|
src += CF;
|
|
ADDB;
|
|
I.regs.b[AL] = dst;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x15, i_adc_axd16)
|
|
{
|
|
DEF_axd16;
|
|
src += CF;
|
|
ADDW;
|
|
I.regs.w[AW] = dst;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x16, i_push_ss)
|
|
{
|
|
PUSH(I.sregs[SS]);
|
|
CLK(2);
|
|
}
|
|
|
|
OP(0x17, i_pop_ss)
|
|
{
|
|
POP(I.sregs[SS]);
|
|
CLK(3);
|
|
no_interrupt = 1;
|
|
}
|
|
|
|
OP(0x18, i_sbb_br8)
|
|
{
|
|
DEF_br8;
|
|
src += CF;
|
|
SUBB;
|
|
PutbackRMByte(ModRM, dst);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x19, i_sbb_wr16)
|
|
{
|
|
DEF_wr16;
|
|
src += CF;
|
|
SUBW;
|
|
PutbackRMWord(ModRM, dst);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x1a, i_sbb_r8b)
|
|
{
|
|
DEF_r8b;
|
|
src += CF;
|
|
SUBB;
|
|
RegByte(ModRM) = dst;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x1b, i_sbb_r16w)
|
|
{
|
|
DEF_r16w;
|
|
src += CF;
|
|
SUBW;
|
|
RegWord(ModRM) = dst;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x1c, i_sbb_ald8)
|
|
{
|
|
DEF_ald8;
|
|
src += CF;
|
|
SUBB;
|
|
I.regs.b[AL] = dst;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x1d, i_sbb_axd16)
|
|
{
|
|
DEF_axd16;
|
|
src += CF;
|
|
SUBW;
|
|
I.regs.w[AW] = dst;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x1e, i_push_ds)
|
|
{
|
|
PUSH(I.sregs[DS]);
|
|
CLK(2);
|
|
}
|
|
|
|
OP(0x1f, i_pop_ds)
|
|
{
|
|
POP(I.sregs[DS]);
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0x20, i_and_br8)
|
|
{
|
|
DEF_br8;
|
|
ANDB;
|
|
PutbackRMByte(ModRM, dst);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x21, i_and_wr16)
|
|
{
|
|
DEF_wr16;
|
|
ANDW;
|
|
PutbackRMWord(ModRM, dst);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x22, i_and_r8b)
|
|
{
|
|
DEF_r8b;
|
|
ANDB;
|
|
RegByte(ModRM) = dst;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x23, i_and_r16w)
|
|
{
|
|
DEF_r16w;
|
|
ANDW;
|
|
RegWord(ModRM) = dst;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x24, i_and_ald8)
|
|
{
|
|
DEF_ald8;
|
|
ANDB;
|
|
I.regs.b[AL] = dst;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x25, i_and_axd16)
|
|
{
|
|
DEF_axd16;
|
|
ANDW;
|
|
I.regs.w[AW] = dst;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x26, i_es)
|
|
{
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[ES] << 4;
|
|
CLK(1);
|
|
nec_instruction[FETCHOP]();
|
|
seg_prefix = false;
|
|
}
|
|
|
|
OP(0x27, i_daa)
|
|
{
|
|
ADJ4(6, 0x60);
|
|
CLK(10);
|
|
}
|
|
|
|
OP(0x28, i_sub_br8)
|
|
{
|
|
DEF_br8;
|
|
SUBB;
|
|
PutbackRMByte(ModRM, dst);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x29, i_sub_wr16)
|
|
{
|
|
DEF_wr16;
|
|
SUBW;
|
|
PutbackRMWord(ModRM, dst);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x2a, i_sub_r8b)
|
|
{
|
|
DEF_r8b;
|
|
SUBB;
|
|
RegByte(ModRM) = dst;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x2b, i_sub_r16w)
|
|
{
|
|
DEF_r16w;
|
|
SUBW;
|
|
RegWord(ModRM) = dst;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x2c, i_sub_ald8)
|
|
{
|
|
DEF_ald8;
|
|
SUBB;
|
|
I.regs.b[AL] = dst;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x2d, i_sub_axd16)
|
|
{
|
|
DEF_axd16;
|
|
SUBW;
|
|
I.regs.w[AW] = dst;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x2e, i_cs)
|
|
{
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[CS] << 4;
|
|
CLK(1);
|
|
nec_instruction[FETCHOP]();
|
|
seg_prefix = false;
|
|
}
|
|
|
|
OP(0x2f, i_das)
|
|
{
|
|
ADJ4(-6, -0x60);
|
|
CLK(10);
|
|
}
|
|
|
|
OP(0x30, i_xor_br8)
|
|
{
|
|
DEF_br8;
|
|
XORB;
|
|
PutbackRMByte(ModRM, dst);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x31, i_xor_wr16)
|
|
{
|
|
DEF_wr16;
|
|
XORW;
|
|
PutbackRMWord(ModRM, dst);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x32, i_xor_r8b)
|
|
{
|
|
DEF_r8b;
|
|
XORB;
|
|
RegByte(ModRM) = dst;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x33, i_xor_r16w)
|
|
{
|
|
DEF_r16w;
|
|
XORW;
|
|
RegWord(ModRM) = dst;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x34, i_xor_ald8)
|
|
{
|
|
DEF_ald8;
|
|
XORB;
|
|
I.regs.b[AL] = dst;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x35, i_xor_axd16)
|
|
{
|
|
DEF_axd16;
|
|
XORW;
|
|
I.regs.w[AW] = dst;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x36, i_ss)
|
|
{
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[SS] << 4;
|
|
CLK(1);
|
|
nec_instruction[FETCHOP]();
|
|
seg_prefix = false;
|
|
}
|
|
|
|
OP(0x37, i_aaa)
|
|
{
|
|
ADJB(6, 1);
|
|
CLK(9);
|
|
}
|
|
|
|
OP(0x38, i_cmp_br8)
|
|
{
|
|
DEF_br8;
|
|
SUBB;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x39, i_cmp_wr16)
|
|
{
|
|
DEF_wr16;
|
|
SUBW;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x3a, i_cmp_r8b)
|
|
{
|
|
DEF_r8b;
|
|
SUBB;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x3b, i_cmp_r16w)
|
|
{
|
|
DEF_r16w;
|
|
SUBW;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x3c, i_cmp_ald8)
|
|
{
|
|
DEF_ald8;
|
|
SUBB;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x3d, i_cmp_axd16)
|
|
{
|
|
DEF_axd16;
|
|
SUBW;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x3e, i_ds)
|
|
{
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[DS] << 4;
|
|
CLK(1);
|
|
nec_instruction[FETCHOP]();
|
|
seg_prefix = false;
|
|
}
|
|
|
|
OP(0x3f, i_aas)
|
|
{
|
|
ADJB(-6, -1);
|
|
CLK(9);
|
|
}
|
|
|
|
OP(0x40, i_inc_ax)
|
|
{
|
|
IncWordReg(AW);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x41, i_inc_cx)
|
|
{
|
|
IncWordReg(CW);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x42, i_inc_dx)
|
|
{
|
|
IncWordReg(DW);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x43, i_inc_bx)
|
|
{
|
|
IncWordReg(BW);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x44, i_inc_sp)
|
|
{
|
|
IncWordReg(SP);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x45, i_inc_bp)
|
|
{
|
|
IncWordReg(BP);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x46, i_inc_si)
|
|
{
|
|
IncWordReg(IX);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x47, i_inc_di)
|
|
{
|
|
IncWordReg(IY);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x48, i_dec_ax)
|
|
{
|
|
DecWordReg(AW);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x49, i_dec_cx)
|
|
{
|
|
DecWordReg(CW);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x4a, i_dec_dx)
|
|
{
|
|
DecWordReg(DW);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x4b, i_dec_bx)
|
|
{
|
|
DecWordReg(BW);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x4c, i_dec_sp)
|
|
{
|
|
DecWordReg(SP);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x4d, i_dec_bp)
|
|
{
|
|
DecWordReg(BP);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x4e, i_dec_si)
|
|
{
|
|
DecWordReg(IX);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x4f, i_dec_di)
|
|
{
|
|
DecWordReg(IY);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x50, i_push_ax)
|
|
{
|
|
PUSH(I.regs.w[AW]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x51, i_push_cx)
|
|
{
|
|
PUSH(I.regs.w[CW]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x52, i_push_dx)
|
|
{
|
|
PUSH(I.regs.w[DW]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x53, i_push_bx)
|
|
{
|
|
PUSH(I.regs.w[BW]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x54, i_push_sp)
|
|
{
|
|
PUSH(I.regs.w[SP]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x55, i_push_bp)
|
|
{
|
|
PUSH(I.regs.w[BP]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x56, i_push_si)
|
|
{
|
|
PUSH(I.regs.w[IX]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x57, i_push_di)
|
|
{
|
|
PUSH(I.regs.w[IY]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x58, i_pop_ax)
|
|
{
|
|
POP(I.regs.w[AW]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x59, i_pop_cx)
|
|
{
|
|
POP(I.regs.w[CW]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x5a, i_pop_dx)
|
|
{
|
|
POP(I.regs.w[DW]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x5b, i_pop_bx)
|
|
{
|
|
POP(I.regs.w[BW]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x5c, i_pop_sp)
|
|
{
|
|
POP(I.regs.w[SP]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x5d, i_pop_bp)
|
|
{
|
|
POP(I.regs.w[BP]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x5e, i_pop_si)
|
|
{
|
|
POP(I.regs.w[IX]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x5f, i_pop_di)
|
|
{
|
|
POP(I.regs.w[IY]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x60, i_pusha)
|
|
{
|
|
uint32_t tmp = I.regs.w[SP];
|
|
PUSH(I.regs.w[AW]);
|
|
PUSH(I.regs.w[CW]);
|
|
PUSH(I.regs.w[DW]);
|
|
PUSH(I.regs.w[BW]);
|
|
PUSH(tmp);
|
|
PUSH(I.regs.w[BP]);
|
|
PUSH(I.regs.w[IX]);
|
|
PUSH(I.regs.w[IY]);
|
|
CLK(9);
|
|
}
|
|
|
|
OP(0x61, i_popa)
|
|
{
|
|
uint32_t tmp;
|
|
POP(I.regs.w[IY]);
|
|
POP(I.regs.w[IX]);
|
|
POP(I.regs.w[BP]);
|
|
POP(tmp);
|
|
POP(I.regs.w[BW]);
|
|
POP(I.regs.w[DW]);
|
|
POP(I.regs.w[CW]);
|
|
POP(I.regs.w[AW]);
|
|
(void)tmp; // We need to uppop something and need tmp
|
|
CLK(8);
|
|
}
|
|
/* BOUND */
|
|
OP(0x62, i_chkind)
|
|
{
|
|
uint32_t low, high, tmp;
|
|
GetModRM;
|
|
low = GetRMWord(ModRM);
|
|
high = GetnextRMWord;
|
|
tmp = RegWord(ModRM);
|
|
|
|
if (tmp < low || tmp > high)
|
|
{
|
|
nec_interrupt(5, 0);
|
|
CLK(7);
|
|
}
|
|
|
|
CLK(13);
|
|
}
|
|
|
|
/* OP 0x64 - 0x67 is nop at V30MZ */
|
|
OP(0x64, i_repnc)
|
|
{
|
|
uint32_t next = FETCHOP;
|
|
uint16_t c = I.regs.w[CW];
|
|
|
|
switch (next) /* Segments */
|
|
{
|
|
case 0x26:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[ES] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
|
|
case 0x2e:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[CS] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
|
|
case 0x36:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[SS] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
|
|
case 0x3e:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[DS] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
}
|
|
|
|
switch (next)
|
|
{
|
|
case 0x6c:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_insb();
|
|
c--;
|
|
} while (c > 0 && !CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0x6d:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_insw();
|
|
c--;
|
|
} while (c > 0 && !CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0x6e:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_outsb();
|
|
c--;
|
|
} while (c > 0 && !CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0x6f:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_outsw();
|
|
c--;
|
|
} while (c > 0 && !CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa4:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_movsb();
|
|
c--;
|
|
} while (c > 0 && !CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa5:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_movsw();
|
|
c--;
|
|
} while (c > 0 && !CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa6:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_cmpsb();
|
|
c--;
|
|
} while (c > 0 && !CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa7:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_cmpsw();
|
|
c--;
|
|
} while (c > 0 && !CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xaa:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_stosb();
|
|
c--;
|
|
} while (c > 0 && !CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xab:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_stosw();
|
|
c--;
|
|
} while (c > 0 && !CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xac:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_lodsb();
|
|
c--;
|
|
} while (c > 0 && !CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xad:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_lodsw();
|
|
c--;
|
|
} while (c > 0 && !CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xae:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_scasb();
|
|
c--;
|
|
} while (c > 0 && !CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xaf:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_scasw();
|
|
c--;
|
|
} while (c > 0 && !CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
default:
|
|
nec_instruction[next]();
|
|
}
|
|
|
|
seg_prefix = false;
|
|
}
|
|
|
|
OP(0x65, i_repc)
|
|
{
|
|
uint32_t next = FETCHOP;
|
|
uint16_t c = I.regs.w[CW];
|
|
|
|
switch (next) /* Segments */
|
|
{
|
|
case 0x26:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[ES] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
|
|
case 0x2e:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[CS] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
|
|
case 0x36:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[SS] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
|
|
case 0x3e:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[DS] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
}
|
|
|
|
switch (next)
|
|
{
|
|
case 0x6c:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_insb();
|
|
c--;
|
|
} while (c > 0 && CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0x6d:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_insw();
|
|
c--;
|
|
} while (c > 0 && CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0x6e:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_outsb();
|
|
c--;
|
|
} while (c > 0 && CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0x6f:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_outsw();
|
|
c--;
|
|
} while (c > 0 && CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa4:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_movsb();
|
|
c--;
|
|
} while (c > 0 && CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa5:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_movsw();
|
|
c--;
|
|
} while (c > 0 && CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa6:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_cmpsb();
|
|
c--;
|
|
} while (c > 0 && CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa7:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_cmpsw();
|
|
c--;
|
|
} while (c > 0 && CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xaa:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_stosb();
|
|
c--;
|
|
} while (c > 0 && CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xab:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_stosw();
|
|
c--;
|
|
} while (c > 0 && CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xac:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_lodsb();
|
|
c--;
|
|
} while (c > 0 && CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xad:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_lodsw();
|
|
c--;
|
|
} while (c > 0 && CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xae:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_scasb();
|
|
c--;
|
|
} while (c > 0 && CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xaf:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_scasw();
|
|
c--;
|
|
} while (c > 0 && CF);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
default:
|
|
nec_instruction[next]();
|
|
}
|
|
|
|
seg_prefix = false;
|
|
}
|
|
|
|
OP(0x68, i_push_d16)
|
|
{
|
|
uint32_t tmp;
|
|
FETCHWORD(tmp);
|
|
PUSH(tmp);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x69, i_imul_d16)
|
|
{
|
|
uint32_t tmp;
|
|
DEF_r16w;
|
|
FETCHWORD(tmp);
|
|
dst = (int32_t)((int16_t)src) * (int32_t)((int16_t)tmp);
|
|
I.CarryVal = I.OverVal = (((int32_t)dst) >> 15 != 0) && (((int32_t)dst) >> 15 != -1);
|
|
RegWord(ModRM) = (int16_t)dst;
|
|
CLKM(4, 3);
|
|
}
|
|
|
|
OP(0x6a, i_push_d8)
|
|
{
|
|
uint32_t tmp = (int16_t)((int16_t)((int8_t)FETCH));
|
|
PUSH(tmp);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x6b, i_imul_d8)
|
|
{
|
|
uint32_t src2;
|
|
DEF_r16w;
|
|
src2 = (int16_t)((int16_t)((int8_t)FETCH));
|
|
dst = (int32_t)((int16_t)src) * (int32_t)((int16_t)src2);
|
|
I.CarryVal = I.OverVal = (((int32_t)dst) >> 15 != 0) && (((int32_t)dst) >> 15 != -1);
|
|
RegWord(ModRM) = (int16_t)dst;
|
|
CLKM(4, 3);
|
|
}
|
|
|
|
OP(0x6c, i_insb)
|
|
{
|
|
PutMemB(ES, I.regs.w[IY], read_port(I.regs.w[DW]));
|
|
I.regs.w[IY] += -2 * I.DF + 1;
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0x6d, i_insw)
|
|
{
|
|
PutMemB(ES, I.regs.w[IY], read_port(I.regs.w[DW]));
|
|
PutMemB(ES, (I.regs.w[IY] + 1) & 0xffff, read_port((I.regs.w[DW] + 1) & 0xffff));
|
|
I.regs.w[IY] += -4 * I.DF + 2;
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0x6e, i_outsb)
|
|
{
|
|
write_port(I.regs.w[DW], GetMemB(DS, I.regs.w[IX]));
|
|
I.regs.w[IX] += -2 * I.DF + 1;
|
|
CLK(7);
|
|
}
|
|
|
|
OP(0x6f, i_outsw)
|
|
{
|
|
write_port(I.regs.w[DW], GetMemB(DS, I.regs.w[IX]));
|
|
write_port((I.regs.w[DW] + 1) & 0xffff, GetMemB(DS, (I.regs.w[IX] + 1) & 0xffff));
|
|
I.regs.w[IX] += -4 * I.DF + 2;
|
|
CLK(7);
|
|
}
|
|
|
|
OP(0x70, i_jo)
|
|
{
|
|
JMP(OF);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x71, i_jno)
|
|
{
|
|
JMP(!OF);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x72, i_jc)
|
|
{
|
|
JMP(CF);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x73, i_jnc)
|
|
{
|
|
JMP(!CF);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x74, i_jz)
|
|
{
|
|
JMP(ZF);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x75, i_jnz)
|
|
{
|
|
JMP(!ZF);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x76, i_jce)
|
|
{
|
|
JMP(CF || ZF);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x77, i_jnce)
|
|
{
|
|
JMP(!(CF || ZF));
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x78, i_js)
|
|
{
|
|
JMP(SF);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x79, i_jns)
|
|
{
|
|
JMP(!SF);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x7a, i_jp)
|
|
{
|
|
JMP(PF);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x7b, i_jnp)
|
|
{
|
|
JMP(!PF);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x7c, i_jl)
|
|
{
|
|
JMP((SF != OF) && (!ZF));
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x7d, i_jnl)
|
|
{
|
|
JMP((ZF) || (SF == OF));
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x7e, i_jle)
|
|
{
|
|
JMP((ZF) || (SF != OF));
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x7f, i_jnle)
|
|
{
|
|
JMP((SF == OF) && (!ZF));
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x80, i_80pre)
|
|
{
|
|
uint32_t dst, src;
|
|
GetModRM;
|
|
dst = GetRMByte(ModRM);
|
|
src = FETCH;
|
|
CLKM(3, 1)
|
|
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
ADDB;
|
|
PutbackRMByte(ModRM, dst);
|
|
break;
|
|
|
|
case 0x08:
|
|
ORB;
|
|
PutbackRMByte(ModRM, dst);
|
|
break;
|
|
|
|
case 0x10:
|
|
src += CF;
|
|
ADDB;
|
|
PutbackRMByte(ModRM, dst);
|
|
break;
|
|
|
|
case 0x18:
|
|
src += CF;
|
|
SUBB;
|
|
PutbackRMByte(ModRM, dst);
|
|
break;
|
|
|
|
case 0x20:
|
|
ANDB;
|
|
PutbackRMByte(ModRM, dst);
|
|
break;
|
|
|
|
case 0x28:
|
|
SUBB;
|
|
PutbackRMByte(ModRM, dst);
|
|
break;
|
|
|
|
case 0x30:
|
|
XORB;
|
|
PutbackRMByte(ModRM, dst);
|
|
break;
|
|
|
|
case 0x38:
|
|
SUBB;
|
|
break; /* CMP */
|
|
}
|
|
}
|
|
|
|
OP(0x81, i_81pre)
|
|
{
|
|
uint32_t dst, src;
|
|
GetModRM;
|
|
dst = GetRMWord(ModRM);
|
|
src = FETCH;
|
|
src += (FETCH << 8);
|
|
CLKM(3, 1)
|
|
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
ADDW;
|
|
PutbackRMWord(ModRM, dst);
|
|
break;
|
|
|
|
case 0x08:
|
|
ORW;
|
|
PutbackRMWord(ModRM, dst);
|
|
break;
|
|
|
|
case 0x10:
|
|
src += CF;
|
|
ADDW;
|
|
PutbackRMWord(ModRM, dst);
|
|
break;
|
|
|
|
case 0x18:
|
|
src += CF;
|
|
SUBW;
|
|
PutbackRMWord(ModRM, dst);
|
|
break;
|
|
|
|
case 0x20:
|
|
ANDW;
|
|
PutbackRMWord(ModRM, dst);
|
|
break;
|
|
|
|
case 0x28:
|
|
SUBW;
|
|
PutbackRMWord(ModRM, dst);
|
|
break;
|
|
|
|
case 0x30:
|
|
XORW;
|
|
PutbackRMWord(ModRM, dst);
|
|
break;
|
|
|
|
case 0x38:
|
|
SUBW;
|
|
break; /* CMP */
|
|
}
|
|
}
|
|
|
|
OP(0x82, i_82pre)
|
|
{
|
|
uint32_t dst, src;
|
|
GetModRM;
|
|
dst = GetRMByte(ModRM);
|
|
src = (uint8_t)((int8_t)FETCH);
|
|
CLKM(3, 1)
|
|
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
ADDB;
|
|
PutbackRMByte(ModRM, dst);
|
|
break;
|
|
|
|
case 0x08:
|
|
ORB;
|
|
PutbackRMByte(ModRM, dst);
|
|
break;
|
|
|
|
case 0x10:
|
|
src += CF;
|
|
ADDB;
|
|
PutbackRMByte(ModRM, dst);
|
|
break;
|
|
|
|
case 0x18:
|
|
src += CF;
|
|
SUBB;
|
|
PutbackRMByte(ModRM, dst);
|
|
break;
|
|
|
|
case 0x20:
|
|
ANDB;
|
|
PutbackRMByte(ModRM, dst);
|
|
break;
|
|
|
|
case 0x28:
|
|
SUBB;
|
|
PutbackRMByte(ModRM, dst);
|
|
break;
|
|
|
|
case 0x30:
|
|
XORB;
|
|
PutbackRMByte(ModRM, dst);
|
|
break;
|
|
|
|
case 0x38:
|
|
SUBB;
|
|
break; /* CMP */
|
|
}
|
|
}
|
|
|
|
OP(0x83, i_83pre)
|
|
{
|
|
uint32_t dst, src;
|
|
GetModRM;
|
|
dst = GetRMWord(ModRM);
|
|
src = (int16_t)((int16_t)((int8_t)FETCH));
|
|
CLKM(3, 1)
|
|
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
ADDW;
|
|
PutbackRMWord(ModRM, dst);
|
|
break;
|
|
|
|
case 0x08:
|
|
ORW;
|
|
PutbackRMWord(ModRM, dst);
|
|
break;
|
|
|
|
case 0x10:
|
|
src += CF;
|
|
ADDW;
|
|
PutbackRMWord(ModRM, dst);
|
|
break;
|
|
|
|
case 0x18:
|
|
src += CF;
|
|
SUBW;
|
|
PutbackRMWord(ModRM, dst);
|
|
break;
|
|
|
|
case 0x20:
|
|
ANDW;
|
|
PutbackRMWord(ModRM, dst);
|
|
break;
|
|
|
|
case 0x28:
|
|
SUBW;
|
|
PutbackRMWord(ModRM, dst);
|
|
break;
|
|
|
|
case 0x30:
|
|
XORW;
|
|
PutbackRMWord(ModRM, dst);
|
|
break;
|
|
|
|
case 0x38:
|
|
SUBW;
|
|
break; /* CMP */
|
|
}
|
|
}
|
|
|
|
OP(0x84, i_test_br8)
|
|
{
|
|
DEF_br8;
|
|
ANDB;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x85, i_test_wr16)
|
|
{
|
|
DEF_wr16;
|
|
ANDW;
|
|
CLKM(2, 1);
|
|
}
|
|
|
|
OP(0x86, i_xchg_br8)
|
|
{
|
|
DEF_br8;
|
|
RegByte(ModRM) = dst;
|
|
PutbackRMByte(ModRM, src);
|
|
CLKM(5, 3);
|
|
}
|
|
|
|
OP(0x87, i_xchg_wr16)
|
|
{
|
|
DEF_wr16;
|
|
RegWord(ModRM) = dst;
|
|
PutbackRMWord(ModRM, src);
|
|
CLKM(5, 3);
|
|
}
|
|
|
|
OP(0x88, i_mov_br8)
|
|
{
|
|
uint8_t src;
|
|
GetModRM;
|
|
src = RegByte(ModRM);
|
|
PutRMByte(ModRM, src);
|
|
CLKM(1, 1);
|
|
}
|
|
|
|
OP(0x89, i_mov_wr16)
|
|
{
|
|
uint16_t src;
|
|
GetModRM;
|
|
src = RegWord(ModRM);
|
|
PutRMWord(ModRM, src);
|
|
CLKM(1, 1);
|
|
}
|
|
|
|
OP(0x8a, i_mov_r8b)
|
|
{
|
|
uint8_t src;
|
|
GetModRM;
|
|
src = GetRMByte(ModRM);
|
|
RegByte(ModRM) = src;
|
|
CLKM(1, 1);
|
|
}
|
|
|
|
OP(0x8b, i_mov_r16w)
|
|
{
|
|
uint16_t src;
|
|
GetModRM;
|
|
src = GetRMWord(ModRM);
|
|
RegWord(ModRM) = src;
|
|
CLKM(1, 1);
|
|
}
|
|
|
|
OP(0x8c, i_mov_wsreg)
|
|
{
|
|
GetModRM;
|
|
PutRMWord(ModRM, I.sregs[(ModRM & 0x38) >> 3]);
|
|
CLKM(1, 1);
|
|
}
|
|
|
|
OP(0x8d, i_lea)
|
|
{
|
|
uint16_t ModRM = FETCH;
|
|
(void)(*GetEA[ModRM])();
|
|
RegWord(ModRM) = EO;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x8e, i_mov_sregw)
|
|
{
|
|
uint16_t src;
|
|
GetModRM;
|
|
src = GetRMWord(ModRM);
|
|
CLKM(3, 2);
|
|
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
I.sregs[ES] = src;
|
|
break; /* mov es,ew */
|
|
|
|
case 0x08:
|
|
I.sregs[CS] = src;
|
|
break; /* mov cs,ew */
|
|
|
|
case 0x10:
|
|
I.sregs[SS] = src;
|
|
break; /* mov ss,ew */
|
|
|
|
case 0x18:
|
|
I.sregs[DS] = src;
|
|
break; /* mov ds,ew */
|
|
|
|
default:;
|
|
}
|
|
|
|
no_interrupt = 1;
|
|
}
|
|
|
|
OP(0x8f, i_popw)
|
|
{
|
|
uint16_t tmp;
|
|
GetModRM;
|
|
POP(tmp);
|
|
PutRMWord(ModRM, tmp);
|
|
CLKM(3, 1);
|
|
}
|
|
|
|
OP(0x90, i_nop)
|
|
{
|
|
CLK(1);
|
|
|
|
/* Cycle skip for idle loops (0: NOP 1: JMP 0) */
|
|
if (no_interrupt == 0 && nec_ICount > 0 && (PEEKOP((I.sregs[CS] << 4) + I.ip)) == 0xeb &&
|
|
(PEEK((I.sregs[CS] << 4) + I.ip + 1)) == 0xfd)
|
|
{
|
|
nec_ICount %= 15;
|
|
}
|
|
}
|
|
|
|
OP(0x91, i_xchg_axcx)
|
|
{
|
|
XchgAWReg(CW);
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0x92, i_xchg_axdx)
|
|
{
|
|
XchgAWReg(DW);
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0x93, i_xchg_axbx)
|
|
{
|
|
XchgAWReg(BW);
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0x94, i_xchg_axsp)
|
|
{
|
|
XchgAWReg(SP);
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0x95, i_xchg_axbp)
|
|
{
|
|
XchgAWReg(BP);
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0x96, i_xchg_axsi)
|
|
{
|
|
XchgAWReg(IX);
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0x97, i_xchg_axdi)
|
|
{
|
|
XchgAWReg(IY);
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0x98, i_cbw)
|
|
{
|
|
I.regs.b[AH] = (I.regs.b[AL] & 0x80) ? 0xff : 0;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x99, i_cwd)
|
|
{
|
|
I.regs.w[DW] = (I.regs.b[AH] & 0x80) ? 0xffff : 0;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0x9a, i_call_far)
|
|
{
|
|
uint32_t tmp, tmp2;
|
|
FETCHWORD(tmp);
|
|
FETCHWORD(tmp2);
|
|
PUSH(I.sregs[CS]);
|
|
PUSH(I.ip);
|
|
I.ip = (int16_t)tmp;
|
|
I.sregs[CS] = (int16_t)tmp2;
|
|
CLK(10);
|
|
}
|
|
|
|
OP(0x9b, i_wait)
|
|
{
|
|
;
|
|
}
|
|
|
|
OP(0x9c, i_pushf)
|
|
{
|
|
PUSH(CompressFlags());
|
|
CLK(2);
|
|
}
|
|
|
|
OP(0x9d, i_popf)
|
|
{
|
|
uint32_t tmp;
|
|
POP(tmp);
|
|
ExpandFlags(tmp);
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0x9e, i_sahf)
|
|
{
|
|
uint32_t tmp = (CompressFlags() & 0xff00) | (I.regs.b[AH] & 0xd5);
|
|
ExpandFlags(tmp);
|
|
CLK(4);
|
|
}
|
|
|
|
OP(0x9f, i_lahf)
|
|
{
|
|
I.regs.b[AH] = CompressFlags() & 0xff;
|
|
CLK(2);
|
|
}
|
|
|
|
OP(0xa0, i_mov_aldisp)
|
|
{
|
|
uint32_t addr;
|
|
FETCHWORD(addr);
|
|
I.regs.b[AL] = GetMemB(DS, addr);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xa1, i_mov_axdisp)
|
|
{
|
|
uint32_t addr;
|
|
FETCHWORD(addr);
|
|
I.regs.b[AL] = GetMemB(DS, addr);
|
|
I.regs.b[AH] = GetMemB(DS, (addr + 1) & 0xffff);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xa2, i_mov_dispal)
|
|
{
|
|
uint32_t addr;
|
|
FETCHWORD(addr);
|
|
PutMemB(DS, addr, I.regs.b[AL]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xa3, i_mov_dispax)
|
|
{
|
|
uint32_t addr;
|
|
FETCHWORD(addr);
|
|
PutMemB(DS, addr, I.regs.b[AL]);
|
|
PutMemB(DS, (addr + 1) & 0xffff, I.regs.b[AH]);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xa4, i_movsb)
|
|
{
|
|
uint32_t tmp = GetMemB(DS, I.regs.w[IX]);
|
|
PutMemB(ES, I.regs.w[IY], tmp);
|
|
I.regs.w[IY] += -2 * I.DF + 1;
|
|
I.regs.w[IX] += -2 * I.DF + 1;
|
|
CLK(5);
|
|
}
|
|
|
|
OP(0xa5, i_movsw)
|
|
{
|
|
uint32_t tmp = GetMemW(DS, I.regs.w[IX]);
|
|
PutMemW(ES, I.regs.w[IY], tmp);
|
|
I.regs.w[IY] += -4 * I.DF + 2;
|
|
I.regs.w[IX] += -4 * I.DF + 2;
|
|
CLK(5);
|
|
}
|
|
|
|
OP(0xa6, i_cmpsb)
|
|
{
|
|
uint32_t src = GetMemB(ES, I.regs.w[IY]);
|
|
uint32_t dst = GetMemB(DS, I.regs.w[IX]);
|
|
SUBB;
|
|
I.regs.w[IY] += -2 * I.DF + 1;
|
|
I.regs.w[IX] += -2 * I.DF + 1;
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xa7, i_cmpsw)
|
|
{
|
|
uint32_t src = GetMemW(ES, I.regs.w[IY]);
|
|
uint32_t dst = GetMemW(DS, I.regs.w[IX]);
|
|
SUBW;
|
|
I.regs.w[IY] += -4 * I.DF + 2;
|
|
I.regs.w[IX] += -4 * I.DF + 2;
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xa8, i_test_ald8)
|
|
{
|
|
DEF_ald8;
|
|
ANDB;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xa9, i_test_axd16)
|
|
{
|
|
DEF_axd16;
|
|
ANDW;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xaa, i_stosb)
|
|
{
|
|
PutMemB(ES, I.regs.w[IY], I.regs.b[AL]);
|
|
I.regs.w[IY] += -2 * I.DF + 1;
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0xab, i_stosw)
|
|
{
|
|
PutMemW(ES, I.regs.w[IY], I.regs.w[AW]);
|
|
I.regs.w[IY] += -4 * I.DF + 2;
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0xac, i_lodsb)
|
|
{
|
|
I.regs.b[AL] = GetMemB(DS, I.regs.w[IX]);
|
|
I.regs.w[IX] += -2 * I.DF + 1;
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0xad, i_lodsw)
|
|
{
|
|
I.regs.w[AW] = GetMemW(DS, I.regs.w[IX]);
|
|
I.regs.w[IX] += -4 * I.DF + 2;
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0xae, i_scasb)
|
|
{
|
|
uint32_t src = GetMemB(ES, I.regs.w[IY]);
|
|
uint32_t dst = I.regs.b[AL];
|
|
SUBB;
|
|
I.regs.w[IY] += -2 * I.DF + 1;
|
|
CLK(4);
|
|
}
|
|
|
|
OP(0xaf, i_scasw)
|
|
{
|
|
uint32_t src = GetMemW(ES, I.regs.w[IY]);
|
|
uint32_t dst = I.regs.w[AW];
|
|
SUBW;
|
|
I.regs.w[IY] += -4 * I.DF + 2;
|
|
CLK(4);
|
|
}
|
|
|
|
OP(0xb0, i_mov_ald8)
|
|
{
|
|
I.regs.b[AL] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xb1, i_mov_cld8)
|
|
{
|
|
I.regs.b[CL] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xb2, i_mov_dld8)
|
|
{
|
|
I.regs.b[DL] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xb3, i_mov_bld8)
|
|
{
|
|
I.regs.b[BL] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xb4, i_mov_ahd8)
|
|
{
|
|
I.regs.b[AH] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xb5, i_mov_chd8)
|
|
{
|
|
I.regs.b[CH] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xb6, i_mov_dhd8)
|
|
{
|
|
I.regs.b[DH] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xb7, i_mov_bhd8)
|
|
{
|
|
I.regs.b[BH] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xb8, i_mov_axd16)
|
|
{
|
|
I.regs.b[AL] = FETCH;
|
|
I.regs.b[AH] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xb9, i_mov_cxd16)
|
|
{
|
|
I.regs.b[CL] = FETCH;
|
|
I.regs.b[CH] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xba, i_mov_dxd16)
|
|
{
|
|
I.regs.b[DL] = FETCH;
|
|
I.regs.b[DH] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xbb, i_mov_bxd16)
|
|
{
|
|
I.regs.b[BL] = FETCH;
|
|
I.regs.b[BH] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xbc, i_mov_spd16)
|
|
{
|
|
I.regs.b[SPL] = FETCH;
|
|
I.regs.b[SPH] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xbd, i_mov_bpd16)
|
|
{
|
|
I.regs.b[BPL] = FETCH;
|
|
I.regs.b[BPH] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xbe, i_mov_sid16)
|
|
{
|
|
I.regs.b[IXL] = FETCH;
|
|
I.regs.b[IXH] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xbf, i_mov_did16)
|
|
{
|
|
I.regs.b[IYL] = FETCH;
|
|
I.regs.b[IYH] = FETCH;
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xc0, i_rotshft_bd8)
|
|
{
|
|
uint32_t src, dst;
|
|
uint8_t c;
|
|
GetModRM;
|
|
src = (uint32_t)GetRMByte(ModRM);
|
|
dst = src;
|
|
c = FETCH;
|
|
c &= 0x1f;
|
|
CLKM(5, 3);
|
|
|
|
if (c)
|
|
{
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
do
|
|
{
|
|
ROL_BYTE;
|
|
c--;
|
|
} while (c > 0);
|
|
|
|
PutbackRMByte(ModRM, (uint8_t)dst);
|
|
break;
|
|
|
|
case 0x08:
|
|
do
|
|
{
|
|
ROR_BYTE;
|
|
c--;
|
|
} while (c > 0);
|
|
|
|
PutbackRMByte(ModRM, (uint8_t)dst);
|
|
break;
|
|
|
|
case 0x10:
|
|
do
|
|
{
|
|
ROLC_BYTE;
|
|
c--;
|
|
} while (c > 0);
|
|
|
|
PutbackRMByte(ModRM, (uint8_t)dst);
|
|
break;
|
|
|
|
case 0x18:
|
|
do
|
|
{
|
|
RORC_BYTE;
|
|
c--;
|
|
} while (c > 0);
|
|
|
|
PutbackRMByte(ModRM, (uint8_t)dst);
|
|
break;
|
|
|
|
case 0x20:
|
|
SHL_BYTE(c);
|
|
I.AuxVal = 1;
|
|
break;//
|
|
|
|
case 0x28:
|
|
SHR_BYTE(c);
|
|
I.AuxVal = 1;
|
|
break;//
|
|
|
|
case 0x30:
|
|
break;
|
|
|
|
case 0x38:
|
|
SHRA_BYTE(c);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
OP(0xc1, i_rotshft_wd8)
|
|
{
|
|
uint32_t src, dst;
|
|
uint8_t c;
|
|
GetModRM;
|
|
src = (uint32_t)GetRMWord(ModRM);
|
|
dst = src;
|
|
c = FETCH;
|
|
c &= 0x1f;
|
|
CLKM(5, 3);
|
|
|
|
if (c)
|
|
{
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
do
|
|
{
|
|
ROL_WORD;
|
|
c--;
|
|
} while (c > 0);
|
|
|
|
PutbackRMWord(ModRM, (int16_t)dst);
|
|
break;
|
|
|
|
case 0x08:
|
|
do
|
|
{
|
|
ROR_WORD;
|
|
c--;
|
|
} while (c > 0);
|
|
|
|
PutbackRMWord(ModRM, (int16_t)dst);
|
|
break;
|
|
|
|
case 0x10:
|
|
do
|
|
{
|
|
ROLC_WORD;
|
|
c--;
|
|
} while (c > 0);
|
|
|
|
PutbackRMWord(ModRM, (int16_t)dst);
|
|
break;
|
|
|
|
case 0x18:
|
|
do
|
|
{
|
|
RORC_WORD;
|
|
c--;
|
|
} while (c > 0);
|
|
|
|
PutbackRMWord(ModRM, (int16_t)dst);
|
|
break;
|
|
|
|
case 0x20:
|
|
SHL_WORD(c);
|
|
I.AuxVal = 1;
|
|
break;
|
|
|
|
case 0x28:
|
|
SHR_WORD(c);
|
|
I.AuxVal = 1;
|
|
break;
|
|
|
|
case 0x30:
|
|
break;
|
|
|
|
case 0x38:
|
|
SHRA_WORD(c);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
OP(0xc2, i_ret_d16)
|
|
{
|
|
uint32_t count = FETCH;
|
|
count += FETCH << 8;
|
|
POP(I.ip);
|
|
I.regs.w[SP] += count;
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xc3, i_ret)
|
|
{
|
|
POP(I.ip);
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xc4, i_les_dw)
|
|
{
|
|
GetModRM;
|
|
int16_t tmp = GetRMWord(ModRM);
|
|
RegWord(ModRM) = tmp;
|
|
I.sregs[ES] = GetnextRMWord;
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xc5, i_lds_dw)
|
|
{
|
|
GetModRM;
|
|
int16_t tmp = GetRMWord(ModRM);
|
|
RegWord(ModRM) = tmp;
|
|
I.sregs[DS] = GetnextRMWord;
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xc6, i_mov_bd8)
|
|
{
|
|
GetModRM;
|
|
PutImmRMByte(ModRM);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xc7, i_mov_wd16)
|
|
{
|
|
GetModRM;
|
|
PutImmRMWord(ModRM);
|
|
CLK(1);
|
|
}
|
|
|
|
OP(0xc8, i_enter)
|
|
{
|
|
uint32_t nb = FETCH;
|
|
uint32_t i, level;
|
|
|
|
CLK(19);
|
|
nb += FETCH << 8;
|
|
level = FETCH;
|
|
PUSH(I.regs.w[BP]);
|
|
I.regs.w[BP] = I.regs.w[SP];
|
|
I.regs.w[SP] -= nb;
|
|
|
|
for (i = 1 ; i < level ; i++)
|
|
{
|
|
PUSH(GetMemW(SS, I.regs.w[BP] - i * 2));
|
|
CLK(4);
|
|
}
|
|
|
|
if (level)
|
|
{
|
|
PUSH(I.regs.w[BP]);
|
|
}
|
|
}
|
|
|
|
OP(0xc9, i_leave)
|
|
{
|
|
I.regs.w[SP] = I.regs.w[BP];
|
|
POP(I.regs.w[BP]);
|
|
CLK(2);
|
|
}
|
|
|
|
OP(0xca, i_retf_d16)
|
|
{
|
|
uint32_t count = FETCH;
|
|
count += FETCH << 8;
|
|
POP(I.ip);
|
|
POP(I.sregs[CS]);
|
|
I.regs.w[SP] += count;
|
|
CLK(9);
|
|
}
|
|
|
|
OP(0xcb, i_retf)
|
|
{
|
|
POP(I.ip);
|
|
POP(I.sregs[CS]);
|
|
CLK(8);
|
|
}
|
|
|
|
OP(0xcc, i_int3)
|
|
{
|
|
nec_interrupt(3, 0);
|
|
CLK(9);
|
|
}
|
|
|
|
OP(0xcd, i_int)
|
|
{
|
|
nec_interrupt(FETCH, 0);
|
|
CLK(10);
|
|
}
|
|
|
|
OP(0xce, i_into)
|
|
{
|
|
if (OF)
|
|
{
|
|
nec_interrupt(4, 0);
|
|
CLK(13);
|
|
}
|
|
else
|
|
{
|
|
CLK(6);
|
|
}
|
|
}
|
|
|
|
OP(0xcf, i_iret)
|
|
{
|
|
POP(I.ip);
|
|
POP(I.sregs[CS]);
|
|
i_popf();
|
|
CLK(10);
|
|
}
|
|
|
|
OP(0xd0, i_rotshft_b)
|
|
{
|
|
uint32_t src, dst;
|
|
GetModRM;
|
|
src = (uint32_t)GetRMByte(ModRM);
|
|
dst = src;
|
|
CLKM(3, 1);
|
|
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
ROL_BYTE;
|
|
PutbackRMByte(ModRM, (uint8_t)dst);
|
|
I.OverVal = (src ^ dst) & 0x80;
|
|
break;
|
|
|
|
case 0x08:
|
|
ROR_BYTE;
|
|
PutbackRMByte(ModRM, (uint8_t)dst);
|
|
I.OverVal = (src ^ dst) & 0x80;
|
|
break;
|
|
|
|
case 0x10:
|
|
ROLC_BYTE;
|
|
PutbackRMByte(ModRM, (uint8_t)dst);
|
|
I.OverVal = (src ^ dst) & 0x80;
|
|
break;
|
|
|
|
case 0x18:
|
|
RORC_BYTE;
|
|
PutbackRMByte(ModRM, (uint8_t)dst);
|
|
I.OverVal = (src ^ dst) & 0x80;
|
|
break;
|
|
|
|
case 0x20:
|
|
SHL_BYTE(1);
|
|
I.OverVal = (src ^ dst) & 0x80;
|
|
I.AuxVal = 1;
|
|
break;
|
|
|
|
case 0x28:
|
|
SHR_BYTE(1);
|
|
I.OverVal = (src ^ dst) & 0x80;
|
|
I.AuxVal = 1;
|
|
break;
|
|
|
|
case 0x30:
|
|
break;
|
|
|
|
case 0x38:
|
|
SHRA_BYTE(1);
|
|
I.OverVal = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
OP(0xd1, i_rotshft_w)
|
|
{
|
|
uint32_t src, dst;
|
|
GetModRM;
|
|
src = (uint32_t)GetRMWord(ModRM);
|
|
dst = src;
|
|
CLKM(3, 1);
|
|
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
ROL_WORD;
|
|
PutbackRMWord(ModRM, (int16_t)dst);
|
|
I.OverVal = (src ^ dst) & 0x8000;
|
|
break;
|
|
|
|
case 0x08:
|
|
ROR_WORD;
|
|
PutbackRMWord(ModRM, (int16_t)dst);
|
|
I.OverVal = (src ^ dst) & 0x8000;
|
|
break;
|
|
|
|
case 0x10:
|
|
ROLC_WORD;
|
|
PutbackRMWord(ModRM, (int16_t)dst);
|
|
I.OverVal = (src ^ dst) & 0x8000;
|
|
break;
|
|
|
|
case 0x18:
|
|
RORC_WORD;
|
|
PutbackRMWord(ModRM, (int16_t)dst);
|
|
I.OverVal = (src ^ dst) & 0x8000;
|
|
break;
|
|
|
|
case 0x20:
|
|
SHL_WORD(1);
|
|
I.AuxVal = 1;
|
|
I.OverVal = (src ^ dst) & 0x8000;
|
|
break;
|
|
|
|
case 0x28:
|
|
SHR_WORD(1);
|
|
I.AuxVal = 1;
|
|
I.OverVal = (src ^ dst) & 0x8000;
|
|
break;
|
|
|
|
case 0x30:
|
|
break;
|
|
|
|
case 0x38:
|
|
SHRA_WORD(1);
|
|
I.AuxVal = 1;
|
|
I.OverVal = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
OP(0xd2, i_rotshft_bcl)
|
|
{
|
|
uint32_t src, dst;
|
|
uint8_t c;
|
|
GetModRM;
|
|
src = (uint32_t)GetRMByte(ModRM);
|
|
dst = src;
|
|
c = I.regs.b[CL];
|
|
CLKM(5, 3);
|
|
c &= 0x1f;
|
|
|
|
if (c)
|
|
{
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
do
|
|
{
|
|
ROL_BYTE;
|
|
c--;
|
|
CLK(1);
|
|
} while (c > 0);
|
|
|
|
PutbackRMByte(ModRM, (uint8_t)dst);
|
|
break;
|
|
|
|
case 0x08:
|
|
do
|
|
{
|
|
ROR_BYTE;
|
|
c--;
|
|
CLK(1);
|
|
} while (c > 0);
|
|
|
|
PutbackRMByte(ModRM, (uint8_t)dst);
|
|
break;
|
|
|
|
case 0x10:
|
|
do
|
|
{
|
|
ROLC_BYTE;
|
|
c--;
|
|
CLK(1);
|
|
} while (c > 0);
|
|
|
|
PutbackRMByte(ModRM, (uint8_t)dst);
|
|
break;
|
|
|
|
case 0x18:
|
|
do
|
|
{
|
|
RORC_BYTE;
|
|
c--;
|
|
CLK(1);
|
|
} while (c > 0);
|
|
|
|
PutbackRMByte(ModRM, (uint8_t)dst);
|
|
break;
|
|
|
|
case 0x20:
|
|
SHL_BYTE(c);
|
|
I.AuxVal = 1;
|
|
break;
|
|
|
|
case 0x28:
|
|
SHR_BYTE(c);
|
|
I.AuxVal = 1;
|
|
break;
|
|
|
|
case 0x30:
|
|
break;
|
|
|
|
case 0x38:
|
|
SHRA_BYTE(c);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
OP(0xd3, i_rotshft_wcl)
|
|
{
|
|
uint32_t src, dst;
|
|
uint8_t c;
|
|
GetModRM;
|
|
src = (uint32_t)GetRMWord(ModRM);
|
|
dst = src;
|
|
c = I.regs.b[CL];
|
|
c &= 0x1f;
|
|
CLKM(5, 3);
|
|
|
|
if (c)
|
|
{
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
do
|
|
{
|
|
ROL_WORD;
|
|
c--;
|
|
CLK(1);
|
|
} while (c > 0);
|
|
|
|
PutbackRMWord(ModRM, (int16_t)dst);
|
|
break;
|
|
|
|
case 0x08:
|
|
do
|
|
{
|
|
ROR_WORD;
|
|
c--;
|
|
CLK(1);
|
|
} while (c > 0);
|
|
|
|
PutbackRMWord(ModRM, (int16_t)dst);
|
|
break;
|
|
|
|
case 0x10:
|
|
do
|
|
{
|
|
ROLC_WORD;
|
|
c--;
|
|
CLK(1);
|
|
} while (c > 0);
|
|
|
|
PutbackRMWord(ModRM, (int16_t)dst);
|
|
break;
|
|
|
|
case 0x18:
|
|
do
|
|
{
|
|
RORC_WORD;
|
|
c--;
|
|
CLK(1);
|
|
} while (c > 0);
|
|
|
|
PutbackRMWord(ModRM, (int16_t)dst);
|
|
break;
|
|
|
|
case 0x20:
|
|
SHL_WORD(c);
|
|
I.AuxVal = 1;
|
|
break;
|
|
|
|
case 0x28:
|
|
SHR_WORD(c);
|
|
I.AuxVal = 1;
|
|
break;
|
|
|
|
case 0x30:
|
|
break;
|
|
|
|
case 0x38:
|
|
SHRA_WORD(c);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
OP(0xd4, i_aam)
|
|
{
|
|
/*uint32_t mult=FETCH; mult=0;*/ I.regs.b[AH] = I.regs.b[AL] / 10;
|
|
I.regs.b[AL] %= 10;
|
|
SetSZPF_Word(I.regs.w[AW]);
|
|
CLK(17);
|
|
}
|
|
|
|
OP(0xd5, i_aad)
|
|
{
|
|
/*uint32_t mult=FETCH; mult=0;*/ I.regs.b[AL] = I.regs.b[AH] * 10 + I.regs.b[AL];
|
|
I.regs.b[AH] = 0;
|
|
SetSZPF_Byte(I.regs.b[AL]);
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xd6, i_setalc)
|
|
{
|
|
I.regs.b[AL] = (CF) ? 0xff : 0x00; /* nop at V30MZ? */
|
|
CLK(3);
|
|
}
|
|
|
|
OP(0xd7, i_trans)
|
|
{
|
|
uint32_t dest = (I.regs.w[BW] + I.regs.b[AL]) & 0xffff;
|
|
I.regs.b[AL] = GetMemB(DS, dest);
|
|
CLK(5);
|
|
}
|
|
|
|
OP(0xd8, i_fpo)
|
|
{
|
|
/*GetModRM;*/ CLK(3); /* nop at V30MZ? */
|
|
}
|
|
|
|
OP(0xe0, i_loopne)
|
|
{
|
|
int8_t disp = (int8_t)FETCH;
|
|
I.regs.w[CW]--;
|
|
|
|
if (!ZF && I.regs.w[CW])
|
|
{
|
|
I.ip = (int16_t)(I.ip + disp);
|
|
CLK(6);
|
|
}
|
|
else
|
|
{
|
|
CLK(3);
|
|
}
|
|
}
|
|
|
|
OP(0xe1, i_loope)
|
|
{
|
|
int8_t disp = (int8_t)FETCH;
|
|
I.regs.w[CW]--;
|
|
|
|
if (ZF && I.regs.w[CW])
|
|
{
|
|
I.ip = (int16_t)(I.ip + disp);
|
|
CLK(6);
|
|
}
|
|
else
|
|
{
|
|
CLK(3);
|
|
}
|
|
}
|
|
|
|
OP(0xe2, i_loop)
|
|
{
|
|
int8_t disp = (int8_t)FETCH;
|
|
I.regs.w[CW]--;
|
|
|
|
if (I.regs.w[CW])
|
|
{
|
|
I.ip = (int16_t)(I.ip + disp);
|
|
CLK(5);
|
|
}
|
|
else
|
|
{
|
|
CLK(2);
|
|
}
|
|
}
|
|
|
|
OP(0xe3, i_jcxz)
|
|
{
|
|
int8_t disp = (int8_t)FETCH;
|
|
|
|
if (I.regs.w[CW] == 0)
|
|
{
|
|
I.ip = (int16_t)(I.ip + disp);
|
|
CLK(4);
|
|
}
|
|
else
|
|
{
|
|
CLK(1);
|
|
}
|
|
}
|
|
|
|
OP(0xe4, i_inal)
|
|
{
|
|
uint8_t port = FETCH;
|
|
I.regs.b[AL] = read_port(port);
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xe5, i_inax)
|
|
{
|
|
uint8_t port = FETCH;
|
|
I.regs.b[AL] = read_port(port);
|
|
I.regs.b[AH] = read_port(port + 1);
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xe6, i_outal)
|
|
{
|
|
uint8_t port = FETCH;
|
|
write_port(port, I.regs.b[AL]);
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xe7, i_outax)
|
|
{
|
|
uint8_t port = FETCH;
|
|
write_port(port, I.regs.b[AL]);
|
|
write_port(port + 1, I.regs.b[AH]);
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xe8, i_call_d16)
|
|
{
|
|
uint32_t tmp;
|
|
FETCHWORD(tmp);
|
|
PUSH(I.ip);
|
|
I.ip = (int16_t)(I.ip + (int16_t)tmp);
|
|
CLK(5);
|
|
}
|
|
|
|
OP(0xe9, i_jmp_d16)
|
|
{
|
|
uint32_t tmp;
|
|
FETCHWORD(tmp);
|
|
//printf("@ %04X -> %04X\n", I.ip-3, tmp);
|
|
I.ip = (int16_t)(I.ip + (int16_t)tmp);
|
|
CLK(4);
|
|
}
|
|
|
|
OP(0xea, i_jmp_far)
|
|
{
|
|
uint32_t tmp, tmp1;
|
|
FETCHWORD(tmp);
|
|
FETCHWORD(tmp1);
|
|
I.sregs[CS] = (int16_t)tmp1;
|
|
I.ip = (int16_t)tmp;
|
|
CLK(7);
|
|
}
|
|
|
|
OP(0xeb, i_jmp_d8)
|
|
{
|
|
int tmp = (int)((int8_t)FETCH);
|
|
CLK(4);
|
|
|
|
if (tmp == -2 && no_interrupt == 0 && nec_ICount > 0)
|
|
{
|
|
nec_ICount %= 12; /* cycle skip */
|
|
}
|
|
|
|
I.ip = (int16_t)(I.ip + tmp);
|
|
}
|
|
|
|
OP(0xec, i_inaldx)
|
|
{
|
|
I.regs.b[AL] = read_port(I.regs.w[DW]);
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xed, i_inaxdx)
|
|
{
|
|
uint32_t port = I.regs.w[DW];
|
|
I.regs.b[AL] = read_port(port);
|
|
I.regs.b[AH] = read_port(port + 1);
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xee, i_outdxal)
|
|
{
|
|
write_port(I.regs.w[DW], I.regs.b[AL]);
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xef, i_outdxax)
|
|
{
|
|
uint32_t port = I.regs.w[DW];
|
|
write_port(port, I.regs.b[AL]);
|
|
write_port(port + 1, I.regs.b[AH]);
|
|
CLK(6);
|
|
}
|
|
|
|
OP(0xf0, i_lock)
|
|
{
|
|
no_interrupt = 1;
|
|
CLK(1);
|
|
}
|
|
|
|
#define THROUGH \
|
|
if(nec_ICount<0){ \
|
|
if(seg_prefix) \
|
|
I.ip-=(uint16_t)3; \
|
|
else \
|
|
I.ip-=(uint16_t)2; \
|
|
break;}
|
|
|
|
OP(0xf2, i_repne)
|
|
{
|
|
uint32_t next = FETCHOP;
|
|
uint16_t c = I.regs.w[CW];
|
|
|
|
switch (next) /* Segments */
|
|
{
|
|
case 0x26:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[ES] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
|
|
case 0x2e:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[CS] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
|
|
case 0x36:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[SS] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
|
|
case 0x3e:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[DS] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
}
|
|
|
|
switch (next)
|
|
{
|
|
case 0x6c:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_insb();
|
|
c--;
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0x6d:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_insw();
|
|
c--;
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0x6e:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_outsb();
|
|
c--;
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0x6f:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_outsw();
|
|
c--;
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa4:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_movsb();
|
|
c--;
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa5:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_movsw();
|
|
c--;
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa6:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_cmpsb();
|
|
c--;
|
|
CLK(3);
|
|
} while (c > 0 && ZF == 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa7:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_cmpsw();
|
|
c--;
|
|
CLK(3);
|
|
} while (c > 0 && ZF == 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xaa:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_stosb();
|
|
c--;
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xab:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_stosw();
|
|
c--;
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xac:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_lodsb();
|
|
c--;
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xad:
|
|
CLK(2);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
i_lodsw();
|
|
c--;
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xae:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_scasb();
|
|
c--;
|
|
CLK(5);
|
|
} while (c > 0 && ZF == 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xaf:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_scasw();
|
|
c--;
|
|
CLK(5);
|
|
} while (c > 0 && ZF == 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
default:
|
|
nec_instruction[next]();
|
|
}
|
|
|
|
seg_prefix = false;
|
|
}
|
|
|
|
OP(0xf3, i_repe)
|
|
{
|
|
uint32_t next = FETCHOP;
|
|
uint16_t c = I.regs.w[CW];
|
|
|
|
switch (next) /* Segments */
|
|
{
|
|
case 0x26:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[ES] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
|
|
case 0x2e:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[CS] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
|
|
case 0x36:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[SS] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
|
|
case 0x3e:
|
|
seg_prefix = true;
|
|
prefix_base = I.sregs[DS] << 4;
|
|
next = FETCHOP;
|
|
CLK(2);
|
|
break;
|
|
}
|
|
|
|
switch (next)
|
|
{
|
|
case 0x6c:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_insb();
|
|
c--;
|
|
CLK(0);
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0x6d:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_insw();
|
|
c--;
|
|
CLK(0);
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0x6e:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_outsb();
|
|
c--;
|
|
CLK(-1);
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0x6f:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_outsw();
|
|
c--;
|
|
CLK(-1);
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa4:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_movsb();
|
|
c--;
|
|
CLK(2);
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa5:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_movsw();
|
|
c--;
|
|
CLK(2);
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa6:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_cmpsb();
|
|
c--;
|
|
CLK(4);
|
|
} while (c > 0 && ZF == 1);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xa7:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_cmpsw();
|
|
c--;
|
|
CLK(4);
|
|
} while (c > 0 && ZF == 1);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xaa:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_stosb();
|
|
c--;
|
|
CLK(3);
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xab:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_stosw();
|
|
c--;
|
|
CLK(3);
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xac:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_lodsb();
|
|
c--;
|
|
CLK(3);
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xad:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_lodsw();
|
|
c--;
|
|
CLK(3);
|
|
} while (c > 0);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xae:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_scasb();
|
|
c--;
|
|
CLK(4);
|
|
} while (c > 0 && ZF == 1);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
case 0xaf:
|
|
CLK(5);
|
|
|
|
if (c)
|
|
{
|
|
do
|
|
{
|
|
THROUGH;
|
|
i_scasw();
|
|
c--;
|
|
CLK(4);
|
|
} while (c > 0 && ZF == 1);
|
|
}
|
|
|
|
I.regs.w[CW] = c;
|
|
break;
|
|
|
|
default:
|
|
nec_instruction[next]();
|
|
}
|
|
|
|
seg_prefix = false;
|
|
}
|
|
|
|
OP(0xf4, i_hlt)
|
|
{
|
|
//printf("Halted @ %04X:%04X...\n", I.sregs[CS], I.ip - 1);
|
|
nec_ICount = 0;
|
|
}
|
|
|
|
|
|
OP(0xf5, i_cmc)
|
|
{
|
|
I.CarryVal = !CF;
|
|
CLK(4);
|
|
}
|
|
|
|
OP(0xf6, i_f6pre)
|
|
{
|
|
uint32_t tmp;
|
|
uint32_t uresult, uresult2;
|
|
int32_t result, result2;
|
|
GetModRM;
|
|
tmp = GetRMByte(ModRM);
|
|
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
tmp &= FETCH;
|
|
I.CarryVal = I.OverVal = I.AuxVal = 0;
|
|
SetSZPF_Byte(tmp);
|
|
CLKM(2, 1);
|
|
break; /* TEST */
|
|
|
|
case 0x08:
|
|
break;
|
|
|
|
case 0x10:
|
|
PutbackRMByte(ModRM, ~tmp);
|
|
CLKM(3, 1);
|
|
break; /* NOT */
|
|
|
|
case 0x18:
|
|
I.CarryVal = (tmp != 0);
|
|
tmp = (~tmp) + 1;
|
|
SetSZPF_Byte(tmp);
|
|
PutbackRMByte(ModRM, tmp & 0xff);
|
|
CLKM(3, 1);
|
|
break; /* NEG */
|
|
|
|
case 0x20:
|
|
uresult = I.regs.b[AL] * tmp;
|
|
I.regs.w[AW] = (int16_t)uresult;
|
|
I.CarryVal = I.OverVal = (I.regs.b[AH] != 0);
|
|
CLKM(4, 3);
|
|
break; /* MULU */
|
|
|
|
case 0x28:
|
|
result = (int16_t)((int8_t)I.regs.b[AL]) * (int16_t)((int8_t)tmp);
|
|
I.regs.w[AW] = (int16_t)result;
|
|
I.CarryVal = I.OverVal = (I.regs.b[AH] != 0);
|
|
CLKM(4, 3);
|
|
break; /* MUL */
|
|
|
|
case 0x30:
|
|
if (tmp)
|
|
{
|
|
DIVUB;
|
|
}
|
|
else
|
|
{
|
|
nec_interrupt(0, 0);
|
|
}
|
|
|
|
CLKM(16, 15);
|
|
break;
|
|
|
|
case 0x38:
|
|
if (tmp)
|
|
{
|
|
DIVB;
|
|
}
|
|
else
|
|
{
|
|
nec_interrupt(0, 0);
|
|
}
|
|
|
|
CLKM(18, 17);
|
|
break;
|
|
}
|
|
}
|
|
|
|
OP(0xf7, i_f7pre)
|
|
{
|
|
uint32_t tmp, tmp2;
|
|
uint32_t uresult, uresult2;
|
|
int32_t result, result2;
|
|
GetModRM;
|
|
tmp = GetRMWord(ModRM);
|
|
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
FETCHWORD(tmp2);
|
|
tmp &= tmp2;
|
|
I.CarryVal = I.OverVal = I.AuxVal = 0;
|
|
SetSZPF_Word(tmp);
|
|
CLKM(2, 1);
|
|
break; /* TEST */
|
|
|
|
case 0x08:
|
|
break;
|
|
|
|
case 0x10:
|
|
PutbackRMWord(ModRM, ~tmp);
|
|
CLKM(3, 1);
|
|
break; /* NOT */
|
|
|
|
case 0x18:
|
|
I.CarryVal = (tmp != 0);
|
|
tmp = (~tmp) + 1;
|
|
SetSZPF_Word(tmp);
|
|
PutbackRMWord(ModRM, tmp & 0xffff);
|
|
CLKM(3, 1);
|
|
break; /* NEG */
|
|
|
|
case 0x20:
|
|
uresult = I.regs.w[AW] * tmp;
|
|
I.regs.w[AW] = uresult & 0xffff;
|
|
I.regs.w[DW] = ((uint32_t)uresult) >> 16;
|
|
I.CarryVal = I.OverVal = (I.regs.w[DW] != 0);
|
|
CLKM(4, 3);
|
|
break; /* MULU */
|
|
|
|
case 0x28:
|
|
result = (int32_t)((int16_t)I.regs.w[AW]) * (int32_t)((int16_t)tmp);
|
|
I.regs.w[AW] = result & 0xffff;
|
|
I.regs.w[DW] = result >> 16;
|
|
I.CarryVal = I.OverVal = (I.regs.w[DW] != 0);
|
|
CLKM(4, 3);
|
|
break; /* MUL */
|
|
|
|
case 0x30:
|
|
if (tmp)
|
|
{
|
|
DIVUW;
|
|
}
|
|
else
|
|
{
|
|
nec_interrupt(0, 0);
|
|
}
|
|
|
|
CLKM(24, 23);
|
|
break;
|
|
|
|
case 0x38:
|
|
if (tmp)
|
|
{
|
|
DIVW;
|
|
}
|
|
else
|
|
{
|
|
nec_interrupt(0, 0);
|
|
}
|
|
|
|
CLKM(25, 24);
|
|
break;
|
|
}
|
|
}
|
|
|
|
OP(0xf8, i_clc)
|
|
{
|
|
I.CarryVal = 0;
|
|
CLK(4);
|
|
}
|
|
|
|
OP(0xf9, i_stc)
|
|
{
|
|
I.CarryVal = 1;
|
|
CLK(4);
|
|
}
|
|
|
|
OP(0xfa, i_di)
|
|
{
|
|
SetIF(0);
|
|
CLK(4);
|
|
}
|
|
|
|
OP(0xfb, i_ei)
|
|
{
|
|
/* STI */
|
|
SetIF(1);
|
|
CLK(4);
|
|
}
|
|
|
|
OP(0xfc, i_cld)
|
|
{
|
|
SetDF(0);
|
|
CLK(4);
|
|
}
|
|
|
|
OP(0xfd, i_std)
|
|
{
|
|
SetDF(1);
|
|
CLK(4);
|
|
}
|
|
|
|
OP(0xfe, i_fepre)
|
|
{
|
|
uint32_t tmp, tmp1;
|
|
GetModRM;
|
|
tmp = GetRMByte(ModRM);
|
|
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
tmp1 = tmp + 1;
|
|
I.OverVal = (tmp == 0x7f);
|
|
SetAF(tmp1, tmp, 1);
|
|
SetSZPF_Byte(tmp1);
|
|
PutbackRMByte(ModRM, (uint8_t)tmp1);
|
|
CLKM(3, 1);
|
|
break; /* INC */
|
|
|
|
case 0x08:
|
|
tmp1 = tmp - 1;
|
|
I.OverVal = (tmp == 0x80);
|
|
SetAF(tmp1, tmp, 1);
|
|
SetSZPF_Byte(tmp1);
|
|
PutbackRMByte(ModRM, (uint8_t)tmp1);
|
|
CLKM(3, 1);
|
|
break; /* DEC */
|
|
}
|
|
}
|
|
|
|
OP(0xff, i_ffpre)
|
|
{
|
|
uint32_t tmp, tmp1;
|
|
GetModRM;
|
|
tmp = GetRMWord(ModRM);
|
|
|
|
switch (ModRM & 0x38)
|
|
{
|
|
case 0x00:
|
|
tmp1 = tmp + 1;
|
|
I.OverVal = (tmp == 0x7fff);
|
|
SetAF(tmp1, tmp, 1);
|
|
SetSZPF_Word(tmp1);
|
|
PutbackRMWord(ModRM, (int16_t)tmp1);
|
|
CLKM(3, 1);
|
|
break; /* INC */
|
|
|
|
case 0x08:
|
|
tmp1 = tmp - 1;
|
|
I.OverVal = (tmp == 0x8000);
|
|
SetAF(tmp1, tmp, 1);
|
|
SetSZPF_Word(tmp1);
|
|
PutbackRMWord(ModRM, (int16_t)tmp1);
|
|
CLKM(3, 1);
|
|
break; /* DEC */
|
|
|
|
case 0x10:
|
|
PUSH(I.ip);
|
|
I.ip = (int16_t)tmp;
|
|
CLKM(6, 5);
|
|
break; /* CALL */
|
|
|
|
case 0x18:
|
|
tmp1 = I.sregs[CS];
|
|
I.sregs[CS] = GetnextRMWord;
|
|
PUSH(tmp1);
|
|
PUSH(I.ip);
|
|
I.ip = tmp;
|
|
CLKM(12, 1);
|
|
break; /* CALL FAR */
|
|
|
|
case 0x20:
|
|
//printf("@ %04X -> %04X\n", I.ip, tmp);
|
|
I.ip = tmp;
|
|
CLKM(5, 4);
|
|
break; /* JMP */
|
|
|
|
case 0x28:
|
|
I.ip = tmp;
|
|
I.sregs[CS] = GetnextRMWord;
|
|
|
|
//printf("New CS: %04X, New IP: %04X\n", I.sregs[CS], I.ip);
|
|
|
|
CLKM(10, 1);
|
|
break; /* JMP FAR */
|
|
|
|
case 0x30:
|
|
PUSH(tmp);
|
|
CLKM(2, 1);
|
|
break;
|
|
|
|
default:;
|
|
}
|
|
}
|
|
|
|
static void i_invalid(void)
|
|
{
|
|
CLK(10);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
uint32_t nec_get_reg(int regnum)
|
|
{
|
|
switch (regnum)
|
|
{
|
|
case NEC_IP:
|
|
return I.ip;
|
|
|
|
case NEC_SP:
|
|
return I.regs.w[SP];
|
|
|
|
case NEC_FLAGS:
|
|
return CompressFlags();
|
|
|
|
case NEC_AW:
|
|
return I.regs.w[AW];
|
|
|
|
case NEC_CW:
|
|
return I.regs.w[CW];
|
|
|
|
case NEC_DW:
|
|
return I.regs.w[DW];
|
|
|
|
case NEC_BW:
|
|
return I.regs.w[BW];
|
|
|
|
case NEC_BP:
|
|
return I.regs.w[BP];
|
|
|
|
case NEC_IX:
|
|
return I.regs.w[IX];
|
|
|
|
case NEC_IY:
|
|
return I.regs.w[IY];
|
|
|
|
case NEC_ES:
|
|
return I.sregs[ES];
|
|
|
|
case NEC_CS:
|
|
return I.sregs[CS];
|
|
|
|
case NEC_SS:
|
|
return I.sregs[SS];
|
|
|
|
case NEC_DS:
|
|
return I.sregs[DS];
|
|
|
|
case NEC_VECTOR:
|
|
return I.int_vector;
|
|
|
|
case NEC_PENDING:
|
|
return I.pending_irq;
|
|
|
|
case NEC_NMI_STATE:
|
|
return I.nmi_state;
|
|
|
|
case NEC_IRQ_STATE:
|
|
return I.irq_state;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void nec_set_reg(int regnum, uint32_t val)
|
|
{
|
|
switch (regnum)
|
|
{
|
|
case NEC_IP:
|
|
I.ip = val;
|
|
break;
|
|
|
|
case NEC_SP:
|
|
I.regs.w[SP] = val;
|
|
break;
|
|
|
|
case NEC_FLAGS:
|
|
ExpandFlags(val);
|
|
break;
|
|
|
|
case NEC_AW:
|
|
I.regs.w[AW] = val;
|
|
break;
|
|
|
|
case NEC_CW:
|
|
I.regs.w[CW] = val;
|
|
break;
|
|
|
|
case NEC_DW:
|
|
I.regs.w[DW] = val;
|
|
break;
|
|
|
|
case NEC_BW:
|
|
I.regs.w[BW] = val;
|
|
break;
|
|
|
|
case NEC_BP:
|
|
I.regs.w[BP] = val;
|
|
break;
|
|
|
|
case NEC_IX:
|
|
I.regs.w[IX] = val;
|
|
break;
|
|
|
|
case NEC_IY:
|
|
I.regs.w[IY] = val;
|
|
break;
|
|
|
|
case NEC_ES:
|
|
I.sregs[ES] = val;
|
|
break;
|
|
|
|
case NEC_CS:
|
|
I.sregs[CS] = val;
|
|
break;
|
|
|
|
case NEC_SS:
|
|
I.sregs[SS] = val;
|
|
break;
|
|
|
|
case NEC_DS:
|
|
I.sregs[DS] = val;
|
|
break;
|
|
|
|
case NEC_VECTOR:
|
|
I.int_vector = val;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
int nec_execute(int cycles)
|
|
{
|
|
int done;
|
|
|
|
nec_ICount = cycles;
|
|
// cpu_type=V30;
|
|
|
|
while (nec_ICount > 0)
|
|
{
|
|
#if 0
|
|
if ((I.sregs[CS] == 0x0600) /* && (I.ip > 0x0050) */)
|
|
{
|
|
int tmp;
|
|
char buffer[256];
|
|
uint8_t op = cpu_readmem20((I.sregs[CS] << 4) + I.ip);
|
|
//Log(TLOG_NORMAL, "NEC v30", "[%04x:%04xh] %02xh '%s' - I=%d\n", I.sregs[CS], I.ip, op, instructionsName[op], I.IF);
|
|
printf("AX: %04X, BX: %04X, CX: %04X, DX: %04X, SI: %04X, DI: %04X, SP: %04X\n",
|
|
I.regs.w[AW], I.regs.w[BW], I.regs.w[CW], I.regs.w[DW],
|
|
I.regs.w[IX], I.regs.w[IY], I.regs.w[SP]);
|
|
printf("CS: %04X, DS: %04X, SS: %04X, ES: %04X\n",
|
|
I.sregs[CS], I.sregs[DS], I.sregs[SS], I.sregs[ES]);
|
|
memset(buffer, 0, 256);
|
|
nec_decode_instruction(I.sregs[CS], I.ip, buffer, 255);
|
|
printf("[%04x:%04xh] %02xh '%s' - I=%d\n", I.sregs[CS], I.ip, op, buffer, I.IF);
|
|
tmp = getchar();
|
|
}
|
|
#endif
|
|
nec_instruction[FETCHOP]();
|
|
// nec_ICount++;
|
|
}
|
|
|
|
done = cycles - nec_ICount;
|
|
|
|
nec_monotonicCycles += done;
|
|
|
|
return done;
|
|
}
|
|
|