3940 lines
60 KiB
C
3940 lines
60 KiB
C
/****************************************************************************
|
|
|
|
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 "nec.h"
|
|
#include "necintrf.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 */
|
|
char 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))
|
|
{
|
|
printf("Something wrong with the interrupt, exiting...\n");
|
|
//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))
|
|
{
|
|
printf("Something wrong with the interrupt, exiting...\n");
|
|
//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;
|
|
}
|
|
}
|
|
|
|
const char *instructionsName[256] =
|
|
{
|
|
"ADD ", "ADD ", "ADD ", "ADD ", "ADD ", "ADD ", "PUSH", "POP ", "OR ", "OR ", "OR ", "OR ", "OR ", "OR ", "PUSH", "----",
|
|
"ADC ", "ADC ", "ADC ", "ADC ", "ADC ", "ADC ", "PUSH", "POP ", "SBB ", "SBB ", "SBB ", "SBB ", "SBB ", "SBB ", "PUSH", "POP ",
|
|
"AND ", "AND ", "AND ", "AND ", "AND ", "AND ", "ES: ", "DAA ", "SUB ", "SUB ", "SUB ", "SUB ", "SUB ", "SUB ", "CS: ", "DAS ",
|
|
"XOR ", "XOR ", "XOR ", "XOR ", "XOR ", "XOR ", "SS: ", "AAA ", "CMP ", "CMP ", "CMP ", "CMP ", "CMP ", "CMP ", "ES: ", "AAS ",
|
|
"INC ", "INC ", "INC ", "INC ", "INC ", "INC ", "INC ", "DEC ", "DEC ", "DEC ", "DEC ", "DEC ", "DEC ", "DEC ", "DEC ", "DEC ",
|
|
"PUSH", "PUSH", "PUSH", "PUSH", "PUSH", "PUSH", "PUSH", "PUSH", "POP ", "POP ", "POP ", "POP ", "POP ", "POP ", "POP ", "POP ",
|
|
"PUSA", "POPA", "BOND", "----", "----", "----", "----", "----", "PUSH", "IMUL", "PUSH", "IMUL", "INS ", "INS ", "OUTS", "OUTS",
|
|
"JO ", "JNO ", "JB ", "JNB ", "JZ ", "JNZ ", "JBE ", "JA ", "JS ", "JNS ", "JPE ", "JPO ", "JL ", "JGE ", "JLE ", "JG ",
|
|
"GPR1", "GPR1", "GPR1", "GPR1", "TEST", "TEST", "XCHG", "XCHG", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "LEA ", "MOV ", "POP ",
|
|
"NOP ", "XCHA", "XCHA", "XCHA", "XCHA", "XCHA", "XCHA", "XCHA", "CBW ", "CWD ", "CALL", "WAIT", "PSHF", "POPF", "SAHF", "LAHF",
|
|
"MOV ", "MOV ", "MOV ", "MOV ", "MOVS", "MOVS", "CMPS", "CMPS", "TEST", "TEST", "STOS", "STOS", "LODS", "LODS", "SCAS", "SCAS",
|
|
"MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ", "MOV ",
|
|
"GRP2", "GRP2", "RETN", "RETN", "LES ", "LDS ", "MOV ", "MOV ", "ENTR", "LEAV", "RETF", "RETF", "INT3", "INT ", "INTO", "IRET",
|
|
"GRP2", "GRP2", "GRP2", "GRP2", "AAM ", "AAD ", "----", "XLAT", "----", "----", "----", "----", "----", "----", "----", "----",
|
|
"LPNZ", "LPZ ", "LOOP", "JCXZ", "IN ", "IN ", "OUT ", "OUT ", "CALL", "JMP ", "JMP ", "JMP ", "IN ", "IN ", "OUT ", "OUT ",
|
|
"LOCK", "----", "RPNZ", "REP ", "HLT ", "CMC ", "GP3A", "GP3B", "CLC ", "STC ", "CLI ", "STI ", "CLD ", "STD ", "GPR4", "GRP5"
|
|
};
|
|
|
|
|
|
int nec_execute(int cycles)
|
|
{
|
|
int done;
|
|
|
|
nec_ICount=cycles;
|
|
// cpu_type=V30;
|
|
|
|
while(nec_ICount>0)
|
|
{
|
|
#if 0
|
|
uint8_t op = cpu_readmem20((I.sregs[CS]<<4) + I.ip);
|
|
printf("[%04x:%04xh] %02xh '%s' - I=%d\n", I.sregs[CS], I.ip,
|
|
op, instructionsName[op], I.IF);
|
|
#endif
|
|
nec_instruction[FETCHOP]();
|
|
// nec_ICount++;
|
|
}
|
|
|
|
done = cycles - nec_ICount;
|
|
|
|
nec_monotonicCycles += done;
|
|
|
|
return done;
|
|
}
|
|
|