#include "headers/types.h" //Basic types
#include "headers/cpu/CPU.h" //CPU needed!
#include "headers/mmu/MMU.h" //MMU needed!
#include "headers/cpu/easyregs.h" //Easy register compatibility!
#include "headers/cpu/modrm.h" //MODR/M compatibility!
#include "headers/cpu/cpusupport.h" //CPU support functions!
#include "headers/hardware/ports.h" //Ports compatibility!
#include "headers/cpu/cpu_OP8086.h" //Our own opcode presets!
#include "headers/mmu/callback.h" //For OPFE!
#include "headers/cpu/flags.h" //Flag support!
#include "headers/cpu/8086_grpOPs.h" //GRP Opcode extensions!
#include "headers/cpu/interrupts.h" //Basic interrupt support!

//When using http://www.mlsite.net/8086/: G=Modr/m mod&r/m adress, E=Reg field in modr/m

//INFO: http://www.mlsite.net/8086/
//Extra info about above: Extension opcodes (GRP1 etc) are contained in the modr/m
//Ammount of instructions in the completed core: 123

//Aftercount: 60-6F,C0-C1, C8-C9, D6, D8-DF, F1, 0F(has been implemented anyways)
//Total count: 30 opcodes undefined.

//Info: Ap = 32-bit segment:offset pointer (data: param 1:word segment, param 2:word offset)

/*

*ADD*=Change! FIND!

*/

//Simplifier!

inline void CPU8086_int(byte interrupt)
{
	CPU8086_hardware_int(interrupt,0,0);
}


inline void CPU8086_hardware_int(byte interrupt, int has_errorcode, uint_32 errorcode) //See int, but for hardware interrupts (IRQs)!
{
	CPU_INT(interrupt); //Save adress to stack (We're going soft int!)!
	if (has_errorcode) //Have error code too?
	{
		CPU_PUSH32(errorcode); //Push error code on stack!
	}
}

inline void CPU8086_IRET()
{
	CPU_IRET(); //IRET!
}

/*

List of hardware interrupts:
0: Division by 0: Attempting to execute DIV/IDIV with divisor==0: IMPLEMENTED
1: Debug/Single step: Breakpoint hit, also after instruction when TRAP flag is set.
3: Breakpoint: INT 3 call: IMPLEMENTED
4: Overflow: When performing arithmetic instructions with signed operands. Called with INTO.
5: Bounds Check: BOUND instruction exceeds limit.
6: Invalid OPCode: Invalid LOCK prefix or invalid OPCode: IMPLEMENTED
7: Device not available: Attempt to use floating point instruction (8087) with no COProcessor.
8: Double fault: Interrupt occurs with no entry in IVT or exception within exception handler.
12: Stack exception: Stack operation exceeds offset FFFFh or a selector pointing to a non-present segment is loaded into SS.
13: CS,DS,ES,FS,GS Segment Overrun: Word memory access at offset FFFFh or an attempt to execute past the end of the code segment.
16: Floating point error: An error with the numeric coprocessor (Divide-by-Zero, Underflow, Overflow...)

*/


//5 Override prefixes! (LOCK, CS, SS, DS, ES)

//Prefix opcodes:
/*
void CPU8086_OPF0() {} //LOCK
void CPU8086_OP2E() {} //CS:
void CPU8086_OP36() {} //SS:
void CPU8086_OP3E() {} //DS:
void CPU8086_OP26() {} //ES:
void CPU8086_OPF2() {} //REPNZ
void CPU8086_OPF3() {} //REPZ
*/

/*

WE START WITH ALL HELP FUNCTIONS

*/


int highestOneBitPosition(uint32_t a)   //For detecting overflow!
{
	int bits=0;
	while (a!=0)
	{
		++bits;
		a>>=1;
	};
	return bits;
}

//For overflow flag manipulation:

bool addition_is_safe(uint32_t a, uint32_t b, byte numbits)
{
	size_t a_bits=highestOneBitPosition(a), b_bits=highestOneBitPosition(b);
	return (a_bits<numbits && b_bits<numbits);
}

bool multiplication_is_safe(uint32_t a, uint32_t b, byte numbits)
{
	size_t a_bits=highestOneBitPosition(a), b_bits=highestOneBitPosition(b);
	return (a_bits+b_bits<=numbits);
}


//First CMP instruction (for debugging) and directly related.

//CMP: Substract and set flags according (Z,S,O,C); Help functions
void CMP_w(unsigned int a, unsigned int b) //Compare instruction!
{
	flag_sub8(a,b); //Flags only!
}

void CMP_b(unsigned char a, unsigned char b)
{
	flag_sub16(a,b); //Flags only!
}


//For data help (fake86)!
extern byte oper1b, oper2b; //Byte variants!
extern word oper1, oper2; //Word variants!
extern byte res8; //Result 8-bit!
extern word res16; //Result 16-bit!
extern byte reg; //For function number!
extern word ea; //From RM offset (GRP5 Opcodes only!)

uint_32 temp1, temp2, temp3, temp4, temp5, temp32, tempaddr32, ea;



//Help functions:
inline void CPU8086_internal_INC16(unsigned int *reg)
{
	if (MMU_invaddr() || (reg==NULL))
	{
		return;
	}
	byte oldcf;
	oldcf = CF;
	oper1 = *reg;
	oper2 = 1;
	res16 = oper1+oper2;
	flag_add16(oper1,oper2);
	CF = oldcf;
	*reg = res16;
}
inline void CPU8086_internal_DEC16(unsigned int *reg)
{
	if (MMU_invaddr())
	{
		return;
	}
	byte oldcf;
	oldcf = CF;
	oper1 = *reg;
	oper2 = 1;
	res16 = oper1-oper2;
	flag_sub16(oper1,oper2);
	CF = oldcf;
	*reg = res16;
}

inline void CPU8086_internal_INC8(unsigned char *reg)
{
	if (MMU_invaddr() || (reg==NULL))
	{
		return;
	}
	oper1b = *reg;
	oper2b = 1;
	flag_add8(oper1b,oper2b);
	*reg = oper1b+oper2b;
}
inline void CPU8086_internal_DEC8(unsigned char *reg)
{
	if (MMU_invaddr())
	{
		return;
	}
	oper1b = *reg;
	oper2b = 1;
	flag_sub8(oper1b,oper2b);
	*reg = oper1b+oper2b;
}

//For ADD
inline void CPU8086_internal_ADD8(unsigned char *dest, unsigned char addition)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	}
	flag_add8(*dest,addition);
	*dest += addition;
}
inline void CPU8086_internal_ADD16(unsigned int *dest, unsigned int addition)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	}
	flag_add16(*dest,addition);
	*dest += addition;
}

//For ADC
inline void CPU8086_internal_ADC8(unsigned char *dest, unsigned char addition)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	}
	flag_adc8(*dest,addition,CF);
	*dest += addition+CF;
}
inline void CPU8086_internal_ADC16(unsigned int *dest, unsigned int addition)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	}
	flag_adc16(*dest,addition,CF);
	*dest += addition+CF;
}


//For OR
inline void CPU8086_internal_OR8(unsigned char *dest, unsigned char src)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	} *dest |= src;
	flag_log8(*dest);
}
inline void CPU8086_internal_OR16(unsigned int *dest, unsigned int src)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	} *dest |= src;
	flag_log16(*dest);
}

//For AND
inline void CPU8086_internal_AND8(unsigned char *dest, unsigned char src)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	} *dest &= src;
	flag_log8(*dest);
}
inline void CPU8086_internal_AND16(unsigned int *dest, unsigned int src)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	} *dest &= src;
	flag_log16(*dest);
}


//For SUB
inline void CPU8086_internal_SUB8(unsigned char *dest, unsigned char addition)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	}
	flag_sub8(*dest,addition);
	*dest -= addition;
}
inline void CPU8086_internal_SUB16(unsigned int *dest, unsigned int addition)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	}
	flag_sub16(*dest,addition);
	*dest -= addition;
}

//For SBB
inline void CPU8086_internal_SBB8(unsigned char *dest, unsigned char addition)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	}
	flag_sbb8(*dest,addition,CF);
	*dest -= addition+CF;
}
inline void CPU8086_internal_SBB16(unsigned int *dest, unsigned int addition)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	}
	flag_sbb16(*dest,addition,CF);
	*dest -= addition+CF;
}

//For XOR
//See AND, but XOR
inline void CPU8086_internal_XOR8(unsigned char *dest, unsigned char src)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	} *dest ^= src;
	flag_log8(*dest);
}
inline void CPU8086_internal_XOR16(unsigned int *dest, unsigned int src)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	} *dest ^= src;
	flag_log16(*dest);
}

//TEST : same as AND, but discarding the result!
inline void CPU8086_internal_TEST8(unsigned char dest, unsigned char src)
{
	unsigned char tmpdest = dest;
	CPU8086_internal_AND8(&tmpdest,src);
}
inline void CPU8086_internal_TEST16(unsigned int dest, unsigned int src)
{
	unsigned int tmpdest = dest;
	CPU8086_internal_AND16(&tmpdest,src);
}

//MOV
inline void CPU8086_internal_MOV8(unsigned char *dest, unsigned char val)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	}  *dest = val;
}
inline void CPU8086_internal_MOV16(unsigned int *dest, unsigned int val)
{
	if (MMU_invaddr() || (dest==NULL))
	{
		return;
	} *dest = val;
}

//LEA
unsigned int getLEA(MODRM_PARAMS *params)
{
	return modrm_lea16(params,2);
}


/*

Stuff for GRP opcodes!

*/


inline void CPU8086_internal_DAA()
{
	if (((AL&0xF)>9) || AF)
	{
		word oper1 = AL+6;
		AL = oper1&255;
		if (oper1&0xFF00)
		{
			CF = 1;
		}
		else
		{
			CF = 0;
		}
		AF = 1;
	}
	else AF = 0;
	if (((AL&0xF0)>0x90) || CF)
	{
		AL += 0x60;
		CF = 1;
	}
	else
	{
		CF = 0;
	}
	flag_szp8(AL);
}
inline void CPU8086_internal_DAS()
{
	if (((AL&0xF)>9) || AF)
	{
		word oper1 = AL-6;
		AL = oper1&255;
		if (oper1&0xFF00)
		{
			CF = 1;
		}
		else
		{
			CF = 0;
		}
		AF = 1;
	}
	else AF = 0;
	if (((AL&0xF0)>0x90) || CF)
	{
		AL -= 0x60;
		CF = 1;
	}
	else
	{
		CF = 0;
	}
	flag_szp8(AL);
}
inline void CPU8086_internal_AAA()
{
	if (((AL&0xF)>9) || AF)
	{
		AL += 6;
		++AH;
		AF = 1;
		CF = 1;
	}
	else
	{
		AF = 0;
		CF = 0;
	}
	AL &= 0xF;
}
inline void CPU8086_internal_AAS()
{
	if (((AL&0xF)>9) || AF)
	{
		AL -= 6;
		--AH;
		AF = 1;
		CF = 1;
	}
	else
	{
		AF = 0;
		CF = 0;
	}
	AL &= 0xF;
}

inline void CPU8086_internal_CBW()
{
	if ((AL&0x80)==0x80)
	{
		AH = 0xFF;
	}
	else
	{
		AH = 0;
	}
}
inline void CPU8086_internal_CWD()
{
	if ((AH&0x80)==0x80)
	{
		DX = 0xFFFF;
	}
	else
	{
		DX = 0;
	}
}

//OK so far!
inline void CPU8086_internal_MOVSB()
{
	MMU_wb(ES,DI,MMU_rb(CPU_segment(CPU_SEGMENT_DS),SI));
	if (DF)
	{
		--SI;
		--DI;
	}
	else
	{
		++SI;
		++DI;
	}
}
inline void CPU8086_internal_MOVSW()
{
	MMU_ww(ES,DI,MMU_rw(CPU_segment(CPU_SEGMENT_DS),SI));
	if (DF)
	{
		SI -= 2;
		DI -= 2;
	}
	else
	{
		SI += 2;
		DI += 2;
	}
}
inline void CPU8086_internal_CMPSB()
{
	CMP_b(MMU_rb(CPU_segment(CPU_SEGMENT_DS),SI),MMU_rb(ES,DI));
	if (DF)
	{
		--SI;
		--DI;
	}
	else
	{
		++SI;
		++DI;
	}
}
inline void CPU8086_internal_CMPSW()
{
	CMP_w(MMU_rw(CPU_segment(CPU_SEGMENT_DS),SI),MMU_rw(ES,DI));
	if (DF)
	{
		SI -= 2;
		DI -= 2;
	}
	else
	{
		SI += 2;
		DI += 2;
	}
}
inline void CPU8086_internal_STOSB()
{
	MMU_wb(ES,DI,AL);
	if (DF)
	{
		--DI;
	}
	else
	{
		++DI;
	}
}
inline void CPU8086_internal_STOSW()
{
	MMU_ww(ES,DI,AX);
	if (DF)
	{
		DI -= 2;
	}
	else
	{
		DI += 2;
	}
}
//OK so far!
inline void CPU8086_internal_LODSB()
{
	AL = MMU_rb(CPU_segment(CPU_SEGMENT_DS),SI);
	if (DF)
	{
		--SI;
	}
	else
	{
		++SI;
	}
}
inline void CPU8086_internal_LODSW()
{
	AX = MMU_rw(CPU_segment(CPU_SEGMENT_DS),SI);
	if (DF)
	{
		SI -= 2;
	}
	else
	{
		SI += 2;
	}
}
inline void CPU8086_internal_SCASB()
{
	CMP_b(MMU_rb(ES,DI),AL);
	if (DF)
	{
		DI--;
	}
	else
	{
		DI++;
	}
}
inline void CPU8086_internal_SCASW()
{
	CMP_w(MMU_rw(ES,DI),AX);
	if (DF)
	{
		DI -= 2;
	}
	else
	{
		DI += 2;
	}
}

inline void CPU8086_internal_RET(int popbytes)
{
	IP = CPU_POP16();    //Near return
	SP += popbytes;
}
inline void CPU8086_internal_RETF(int popbytes)
{
	IP = CPU_POP16();    //Far return
	CS = CPU_POP16();
	SP += popbytes;
}

inline void CPU8086_internal_INTO()
{
	if (OF)
	{
		CPU8086_int(4);
	}
}

inline void CPU8086_internal_AAM(unsigned char data)
{
	if (!data)
	{
		CPU8086_int(0);    //AAM
		return;
	}
	AH = ((AL/data)&0xFF);
	AL = ((AL%data)&0xFF);
	flag_szp16(AX);
}
inline void CPU8086_internal_AAD(unsigned char data)
{
	AL = (((AH*data)+AL)&0xFF);    //AAD
	AH = 0;
	flag_szp16((AH*data)+AL);
	SF = 0;
}

inline void CPU8086_internal_XLAT()
{
	AL = MMU_rb(CPU_segment(CPU_SEGMENT_DS),BX+AL);    //XLAT
}

//ALL ABOVE SHOULD BE OK ACCORDING TO FAKE86 CPU.C

/*

NOW THE REAL OPCODES!

*/














void CPU8086_OP00()
{
	MODRM_PARAMS params;    //ADD modrm8(modrm), modrm8(reg)
	modrm_readparams(&params,1,0);
	CPU8086_internal_ADD8(modrm_addr8(&params,2),modrm_read8(&params,1));
}
void CPU8086_OP01()
{
	MODRM_PARAMS params;    //ADD modrm16(modrm), modrm16(reg)
	modrm_readparams(&params,2,0);
	CPU8086_internal_ADD16(modrm_addr16(&params,2),modrm_read16(&params,1));
}
void CPU8086_OP02()
{
	MODRM_PARAMS params;    //ADD modrm8(reg), modrm8(modrm)
	modrm_readparams(&params,1,0);
	CPU8086_internal_ADD8(modrm_addr8(&params,1),modrm_read8(&params,2));
}
void CPU8086_OP03()
{
	MODRM_PARAMS params;    //ADD modrm16(reg), modrm16(modrm)
	modrm_readparams(&params,2,0);
	CPU8086_internal_ADD16(modrm_addr16(&params,1),modrm_read16(&params,2));
}
void CPU8086_OP04()
{
	CPU8086_internal_ADD8(&AL,CPU_readOP());    //4=AL,imm8
}
void CPU8086_OP05()
{
	CPU8086_internal_ADD16(&AX,CPU_readOPw());    //5=AX,imm16
}
void CPU8086_OP06()
{
	CPU_PUSH16(&ES);    //PUSH ES
}
void CPU8086_OP07()
{
	ES = CPU_POP16();    //POP ES
}
void CPU8086_OP08()
{
	MODRM_PARAMS params;    //ADD modrm8(modrm), modrm8(reg)
	modrm_readparams(&params,1,0);
	CPU8086_internal_OR8(modrm_addr8(&params,2),modrm_read8(&params,1));
}
void CPU8086_OP09()
{
	MODRM_PARAMS params;    //ADD modrm16(modrm), modrm16(reg)
	modrm_readparams(&params,2,0);
	CPU8086_internal_OR16(modrm_addr16(&params,2),modrm_read16(&params,1));
}
void CPU8086_OP0A()
{
	MODRM_PARAMS params;    //ADD modrm8(reg), modrm8(modrm)
	modrm_readparams(&params,1,0);
	CPU8086_internal_OR8(modrm_addr8(&params,1),modrm_read8(&params,2));
}
void CPU8086_OP0B()
{
	MODRM_PARAMS params;    //ADD modrm16(reg), modrm16(modrm)
	modrm_readparams(&params,2,0);
	CPU8086_internal_OR16(modrm_addr16(&params,1),modrm_read16(&params,2));
}
void CPU8086_OP0C()
{
	CPU8086_internal_OR8(&AL,CPU_readOP());    //4=AL,imm8
}
void CPU8086_OP0D()
{
	CPU8086_internal_OR16(&AX,CPU_readOPw());    //5=AX,imm16
}
void CPU8086_OP0E()
{
	CPU_PUSH16(&CS);    //PUSH CS
}
void CPU8086_OP10()
{
	MODRM_PARAMS params;    //ADD modrm8(modrm), modrm8(reg)
	modrm_readparams(&params,1,0);
	CPU8086_internal_ADC8(modrm_addr8(&params,2),modrm_read8(&params,1));
}
void CPU8086_OP11()
{
	MODRM_PARAMS params;    //ADD modrm16(modrm), modrm16(reg)
	modrm_readparams(&params,2,0);
	CPU8086_internal_ADC16(modrm_addr16(&params,2),modrm_read16(&params,1));
}
void CPU8086_OP12()
{
	MODRM_PARAMS params;    //ADD modrm8(reg), modrm8(modrm)
	modrm_readparams(&params,1,0);
	CPU8086_internal_ADC8(modrm_addr8(&params,1),modrm_read8(&params,2));
}
void CPU8086_OP13()
{
	MODRM_PARAMS params;    //ADD modrm16(reg), modrm16(modrm)
	modrm_readparams(&params,2,0);
	CPU8086_internal_ADC16(modrm_addr16(&params,1),modrm_read16(&params,2));
}
void CPU8086_OP14()
{
	CPU8086_internal_ADC8(&AL,CPU_readOP());    //4=AL,imm8
}
void CPU8086_OP15()
{
	CPU8086_internal_ADC16(&AX,CPU_readOPw());    //5=AX,imm16
}
void CPU8086_OP16()
{
	CPU_PUSH16(&SS);    //PUSH SS
}
void CPU8086_OP17()
{
	SS = CPU_POP16();    //POP SS
}
void CPU8086_OP18()
{
	MODRM_PARAMS params;    //SBB modrm8(modrm), modrm8(reg)
	modrm_readparams(&params,1,0);
	CPU8086_internal_SBB8(modrm_addr8(&params,2),(modrm_read8(&params,1)));
}
void CPU8086_OP19()
{
	MODRM_PARAMS params;    //SBB modrm16(modrm), modrm16(reg)
	modrm_readparams(&params,2,0);
	CPU8086_internal_SBB16(modrm_addr16(&params,2),(modrm_read16(&params,1)));
}
void CPU8086_OP1A()
{
	MODRM_PARAMS params;    //SBB modrm8(reg), modrm8(modrm)
	modrm_readparams(&params,1,0);
	CPU8086_internal_SBB8(modrm_addr8(&params,1),(modrm_read8(&params,2)));
}
void CPU8086_OP1B()
{
	MODRM_PARAMS params;    //SBB modrm16(reg), modrm16(modrm)
	modrm_readparams(&params,2,0);
	CPU8086_internal_SBB16(modrm_addr16(&params,1),(modrm_read16(&params,2)));
}
void CPU8086_OP1C()
{
	CPU8086_internal_SBB8(&AL,CPU_readOP());    //4=AL,imm8
}
void CPU8086_OP1D()
{
	CPU8086_internal_SBB16(&AX,CPU_readOPw());    //5=AX,imm16
}
void CPU8086_OP1E()
{
	CPU_PUSH16(&DS);    //PUSH DS
}
void CPU8086_OP1F()
{
	DS = CPU_POP16();    //POP DS
}
void CPU8086_OP20()
{
	MODRM_PARAMS params;    //AND modrm8(modrm), modrm8(reg)
	modrm_readparams(&params,1,0);
	CPU8086_internal_AND8(modrm_addr8(&params,2),modrm_read8(&params,1));
}
void CPU8086_OP21()
{
	MODRM_PARAMS params;    //AND modrm16(modrm), modrm16(reg)
	modrm_readparams(&params,2,0);
	CPU8086_internal_AND16(modrm_addr16(&params,2),modrm_read16(&params,1));
}
void CPU8086_OP22()
{
	MODRM_PARAMS params;    //AND modrm8(reg), modrm8(modrm)
	modrm_readparams(&params,1,0);
	CPU8086_internal_AND8(modrm_addr8(&params,1),modrm_read8(&params,2));
}
void CPU8086_OP23()
{
	MODRM_PARAMS params;    //AND modrm16(reg), modrm16(modrm)
	modrm_readparams(&params,2,0);
	CPU8086_internal_AND16(modrm_addr16(&params,1),modrm_read16(&params,2));
}
void CPU8086_OP24()
{
	CPU8086_internal_AND8(&AL,CPU_readOP());    //4=AL,imm8
}
void CPU8086_OP25()
{
	CPU8086_internal_AND16(&AX,CPU_readOPw());    //5=AX,imm16
}
void CPU8086_OP27()
{
	CPU8086_internal_DAA();    //DAA?
}
void CPU8086_OP28()
{
	MODRM_PARAMS params;    //SUB modrm8(modrm), modrm8(reg)
	modrm_readparams(&params,1,0);
	CPU8086_internal_SUB8(modrm_addr8(&params,2),(modrm_read8(&params,1)));
}
void CPU8086_OP29()
{
	MODRM_PARAMS params;    //SUB modrm16(modrm), modrm16(reg)
	modrm_readparams(&params,2,0);
	CPU8086_internal_SUB16(modrm_addr16(&params,2),(modrm_read16(&params,1)));
}
void CPU8086_OP2A()
{
	MODRM_PARAMS params;    //SUB modrm8(reg), modrm8(modrm)
	modrm_readparams(&params,1,0);
	CPU8086_internal_SUB8(modrm_addr8(&params,1),(modrm_read8(&params,2)));
}
void CPU8086_OP2B()
{
	MODRM_PARAMS params;    //SUB modrm16(reg), modrm16(modrm)
	modrm_readparams(&params,2,0);
	CPU8086_internal_SUB16(modrm_addr16(&params,1),(modrm_read16(&params,2)));
}
void CPU8086_OP2C()
{
	CPU8086_internal_SUB8(&AL,CPU_readOP());    //4=AL,imm8
}
void CPU8086_OP2D()
{
	CPU8086_internal_SUB16(&AX,CPU_readOPw());    //5=AX,imm16
}
void CPU8086_OP2F()
{
	CPU8086_internal_DAS();    //DAS?
}
void CPU8086_OP30()
{
	MODRM_PARAMS params;    //XOR modrm8(modrm), modrm8(reg)
	modrm_readparams(&params,1,0);
	CPU8086_internal_XOR8(modrm_addr8(&params,2),modrm_read8(&params,1));
}
void CPU8086_OP31()
{
	MODRM_PARAMS params;    //XOR modrm16(modrm), modrm16(reg)
	modrm_readparams(&params,2,0);
	CPU8086_internal_XOR16(modrm_addr16(&params,2),modrm_read16(&params,1));
}
void CPU8086_OP32()
{
	MODRM_PARAMS params;    //XOR modrm8(reg), modrm8(modrm)
	modrm_readparams(&params,1,0);
	CPU8086_internal_XOR8(modrm_addr8(&params,1),modrm_read8(&params,2));
}
void CPU8086_OP33()
{
	MODRM_PARAMS params;    //XOR modrm16(reg), modrm16(modrm)
	modrm_readparams(&params,2,0);
	CPU8086_internal_XOR16(modrm_addr16(&params,1),modrm_read16(&params,2));
}
void CPU8086_OP34()
{
	CPU8086_internal_XOR8(&AL,CPU_readOP());    //4=AL,imm8
}
void CPU8086_OP35()
{
	CPU8086_internal_XOR16(&AX,CPU_readOPw());    //5=AX,imm16
}
void CPU8086_OP37()
{
	CPU8086_internal_AAA();    //AAA?
}
void CPU8086_OP38()
{
	MODRM_PARAMS params;    //CMP modr/m(byte), modrm.reg
	modrm_readparams(&params,1,0);
	CMP_b(modrm_read8(&params,2),modrm_read8(&params,1));
}
void CPU8086_OP39()
{
	MODRM_PARAMS params;    //CMP modr/m(word), modrm.reg
	modrm_readparams(&params,2,0);
	CMP_w(modrm_read16(&params,2),modrm_read16(&params,1));
}
void CPU8086_OP3A()
{
	MODRM_PARAMS params;    //CMP modrm.reg, modr/m(byte) [OR: reverse OP38]
	modrm_readparams(&params,1,0);
	CMP_b(modrm_read8(&params,1),modrm_read8(&params,2));
}
void CPU8086_OP3B()
{
	MODRM_PARAMS params;    //CMP modrm.reg, modr/m(word) [OR: reverse OP39]
	modrm_readparams(&params,2,0);
	CMP_w(modrm_read16(&params,1),modrm_read16(&params,2));
}
void CPU8086_OP3C()
{
	CMP_b(AL,CPU_readOP());    //CMP AL, imm8
}
void CPU8086_OP3D()
{
	CMP_w(AX,CPU_readOPw());    //CMP AX, imm16
}
void CPU8086_OP3F()
{
	CPU8086_internal_AAS();    //AAS?
}
void CPU8086_OP40()
{
	CPU8086_internal_INC16(&AX);    //INC AX
}
void CPU8086_OP41()
{
	CPU8086_internal_INC16(&CX);    //INC CX
}
void CPU8086_OP42()
{
	CPU8086_internal_INC16(&DX);    //INC DX
}
void CPU8086_OP43()
{
	CPU8086_internal_INC16(&BX);    //INC BX
}
void CPU8086_OP44()
{
	CPU8086_internal_INC16(&SP);    //INC SP
}
void CPU8086_OP45()
{
	CPU8086_internal_INC16(&BP);    //INC BP
}
void CPU8086_OP46()
{
	CPU8086_internal_INC16(&SI);    //INC SI
}
void CPU8086_OP47()
{
	CPU8086_internal_INC16(&DI);    //INC DI
}
void CPU8086_OP48()
{
	CPU8086_internal_DEC16(&AX);    //DEC AX
}
void CPU8086_OP49()
{
	CPU8086_internal_DEC16(&CX);    //DEC CX
}
void CPU8086_OP4A()
{
	CPU8086_internal_DEC16(&DX);    //DEC DX
}
void CPU8086_OP4B()
{
	CPU8086_internal_DEC16(&BX);    //DEC BX
}
void CPU8086_OP4C()
{
	CPU8086_internal_DEC16(&SP);    //DEC SP
}
void CPU8086_OP4D()
{
	CPU8086_internal_DEC16(&BP);    //DEC BP
}
void CPU8086_OP4E()
{
	CPU8086_internal_DEC16(&SI);    //DEC SI
}
void CPU8086_OP4F()
{
	CPU8086_internal_DEC16(&DI);    //DEC DI
}
void CPU8086_OP50()
{
	CPU_PUSH16(&AX);    //PUSH AX
}
void CPU8086_OP51()
{
	CPU_PUSH16(&CX);    //PUSH CX
}
void CPU8086_OP52()
{
	CPU_PUSH16(&DX);    //PUSH DX
}
void CPU8086_OP53()
{
	CPU_PUSH16(&BX);    //PUSH BX
}
void CPU8086_OP54()
{
	CPU_PUSH16(&SP);    //PUSH SP
}
void CPU8086_OP55()
{
	CPU_PUSH16(&BP);    //PUSH BP
}
void CPU8086_OP56()
{
	CPU_PUSH16(&SI);    //PUSH SI
}
void CPU8086_OP57()
{
	CPU_PUSH16(&DI);    //PUSH DI
}
void CPU8086_OP58()
{
	AX = CPU_POP16();    //POP AX
}
void CPU8086_OP59()
{
	CX = CPU_POP16();    //POP CX
}
void CPU8086_OP5A()
{
	DX = CPU_POP16();    //POP DX
}
void CPU8086_OP5B()
{
	BX = CPU_POP16();    //POP BX
}
void CPU8086_OP5C()
{
	SP = MMU_rw(SS,SP);    //POP SP
}
void CPU8086_OP5D()
{
	BP = CPU_POP16();    //POP BP
}
void CPU8086_OP5E()
{
	SI = CPU_POP16();    //POP SI
}
void CPU8086_OP5F()
{
	DI = CPU_POP16();    //POP DI
}
void CPU8086_OP70()
{
	signed char rel8;    //JO rel8  : (OF=1)
	rel8 = imm8();
	if (OF)
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP71()
{
	signed char rel8;    //JNO rel8 : (OF=0)
	rel8 = imm8();
	if (!OF)
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP72()
{
	signed char rel8;    //JB rel8  : (CF=1)
	rel8 = imm8();
	if (CF)
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP73()
{
	signed char rel8;    //JNB rel8 : (CF=0)
	rel8 = imm8();
	if (!CF)
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP74()
{
	signed char rel8;    //JZ rel8  : (ZF=1)
	rel8 = imm8();
	if (ZF)
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP75()
{
	signed char rel8;    //JNZ rel8 : (ZF=0)
	rel8 = imm8();
	if (!ZF)
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP76()
{
	signed char rel8;    //JBE rel8 : (CF=1|ZF=1)
	rel8 = imm8();
	if (CF||ZF)
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP77()
{
	signed char rel8;    //JA rel8  : (CF=0&ZF=0)
	rel8 = imm8();
	if ((!CF)&&(!ZF))
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP78()
{
	signed char rel8;    //JS rel8  : (SF=1)
	rel8 = imm8();
	if (SF)
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP79()
{
	signed char rel8;    //JNS rel8 : (SF=0)
	rel8 = imm8();
	if (!SF)
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP7A()
{
	signed char rel8;    //JPE rel8 : (PF=1)
	rel8 = imm8();
	if (PF)
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP7B()
{
	signed char rel8;    //JPO rel8 : (PF=0)
	rel8 = imm8();
	if (!PF)
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP7C()
{
	signed char rel8;    //JL rel8  : (SF!=OF)
	rel8 = imm8();
	if (SF!=OF)
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP7D()
{
	signed char rel8;    //JGE rel8 : (SF=OF)
	rel8 = imm8();
	if (SF==OF)
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP7E()
{
	signed char rel8;    //JLE rel8 : (ZF|(SF!=OF))
	rel8 = imm8();
	if ((SF!=OF) || ZF)
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP7F()
{
	signed char rel8;    //JG rel8  : ((ZF=0)|SF=OF)
	rel8 = imm8();
	if (!ZF && (SF==OF))
	{
		IP += rel8; /* JUMP to destination? */
	}
}
void CPU8086_OP84()
{
	MODRM_PARAMS params;    //TEST modrm8(reg), modrm8(modrm)
	modrm_readparams(&params,1,0);
	CPU8086_internal_TEST8(modrm_read8(&params,1),modrm_read8(&params,2));
}
void CPU8086_OP85()
{
	MODRM_PARAMS params;    //TEST modrm16(reg), modrm16(modrm)
	modrm_readparams(&params,2,0);
	CPU8086_internal_TEST16(modrm_read16(&params,1),modrm_read16(&params,2));
}
void CPU8086_OP86()
{
	MODRM_PARAMS params;    //XCHG reg8,r/m8
	modrm_readparams(&params,1,0);
	unsigned char oldreg = modrm_read8(&params,1);
	modrm_write8(&params,1,modrm_read8(&params,2));
	modrm_write8(&params,2,oldreg);
}
void CPU8086_OP87()
{
	MODRM_PARAMS params;    //XCHG reg16,r/m16
	modrm_readparams(&params,2,0);
	unsigned int oldreg = modrm_read16(&params,1);
	modrm_write16(&params,1,modrm_read16(&params,2));
	modrm_write16(&params,2,oldreg);
}
void CPU8086_OP88()
{
	MODRM_PARAMS params;    //MOV modrm8(modrm), modrm8(reg)
	modrm_readparams(&params,1,0);
	CPU8086_internal_MOV8(modrm_addr8(&params,2),modrm_read8(&params,1));
}
void CPU8086_OP89()
{
	MODRM_PARAMS params;    //MOV modrm16(modrm), modrm16(reg)
	modrm_readparams(&params,2,0);
	CPU8086_internal_MOV16(modrm_addr16(&params,2),modrm_read16(&params,1));
}
void CPU8086_OP8A()
{
	MODRM_PARAMS params;    //MOV modrm8(reg), modrm8(modrm)
	modrm_readparams(&params,1,0);
	CPU8086_internal_MOV8(modrm_addr8(&params,1),modrm_read8(&params,2));
}
void CPU8086_OP8B()
{
	MODRM_PARAMS params;    //MOV modrm16(reg), modrm16(modrm)
	modrm_readparams(&params,2,0);
	CPU8086_internal_MOV16(modrm_addr16(&params,1),modrm_read16(&params,2));
}
void CPU8086_OP8C()
{
	MODRM_PARAMS params;    //MOV modrm16(modrm), modrm16(reg(segment register))
	modrm_readparams(&params,2,2);
	CPU8086_internal_MOV16(modrm_addr16(&params,2),modrm_read16(&params,1));
}
void CPU8086_OP8D()
{
	MODRM_PARAMS params;    //LEA (modrm,1), modrm(memory) : Just give the adress, not the value!
	modrm_readparams(&params,2,0);
	CPU8086_internal_MOV16(modrm_addr16(&params,1),getLEA(&params));
}
void CPU8086_OP8E()
{
	MODRM_PARAMS params;    //MOV modrm16(reg(segment register)), modrm16(modrm)
	modrm_readparams(&params,2,2);
	CPU8086_internal_MOV16(modrm_addr16(&params,1),modrm_read16(&params,2));
}
void CPU8086_OP8F()
{
	MODRM_PARAMS params;    //POP r/m(word)
	modrm_readparams(&params,2,0);
	modrm_write16(&params,2,CPU_POP16());
}
void CPU8086_OP90()
{
	CPU8086_internal_MOV16(&AX,AX);    //NOP (XCHG AX,AX)
}
void CPU8086_OP91()
{
	unsigned int oldreg = CX;    //XCHG AX,CX
	CX = AX;
	AX = oldreg;
}
void CPU8086_OP92()
{
	unsigned int oldreg = DX;    //XCHG AX,DX
	DX = AX;
	AX = oldreg;
}
void CPU8086_OP93()
{
	unsigned int oldreg = BX;    //XCHG AX,BX
	BX = AX;
	AX = oldreg;
}
void CPU8086_OP94()
{
	unsigned int oldreg = SP;    //XCHG AX,SP
	SP = AX;
	AX = oldreg;
}
void CPU8086_OP95()
{
	unsigned int oldreg = BP;    //XCHG AX,BP
	BP = AX;
	AX = oldreg;
}
void CPU8086_OP96()
{
	unsigned int oldreg = SI;    //XCHG AX,SI
	SI = AX;
	AX = oldreg;
}
void CPU8086_OP97()
{
	unsigned int oldreg = DI;    //XCHG AX,DI
	DI = AX;
	AX = oldreg;
}
void CPU8086_OP98()
{
	CPU8086_internal_CBW();    //CBW : sign extend AL to AX (8088+)
}
void CPU8086_OP99()
{
	CPU8086_internal_CWD();    //CWD : sign extend AX to DXAX (8088+)
}
void CPU8086_OP9A()
{
	++CPU.calllayer;    //CALL Ap
	unsigned int offset = CPU_readOPw();
	unsigned int segment = CPU_readOPw();
	CPU_PUSH16(&CS);
	CPU_PUSH16(&IP);
	CS = segment;
	IP = offset;
}
void CPU8086_OP9B()
{
	CPU.wait = 1;    //9B: WAIT : wait for TEST pin activity. (Edit: on interrupts or 8087+!!!)
}
void CPU8086_OP9C()
{
	word temp;    //PUSHF
	temp = FLAGS|0xF800;
	CPU_PUSH16(&temp);
}
void CPU8086_OP9D()
{
	FLAGS = CPU_POP16();    //POPF
}
void CPU8086_OP9E()
{
	FLAGS = ((FLAGS&0xFF00)|AH);    //SAHF : Save AH to lower half of FLAGS.
}
void CPU8086_OP9F()
{
	AH = (FLAGS&0xFF);    //LAHF : Load lower half of FLAGS into AH.
}
void CPU8086_OPA0()
{
	CPU8086_internal_MOV8(&AL,MMU_rb(CPU_segment(CPU_SEGMENT_DS),CPU_readOPw()));    //MOV AL,[imm16]
}
void CPU8086_OPA1()
{
	CPU8086_internal_MOV16(&AX,MMU_rw(CPU_segment(CPU_SEGMENT_DS),CPU_readOPw()));    //MOV AX,[imm16]
}
void CPU8086_OPA2()
{
	CPU8086_internal_MOV8(MMU_ptr(CPU_segment(CPU_SEGMENT_DS),CPU_readOPw()),AL);    //MOV [imm16],AL
}
void CPU8086_OPA3()
{
	CPU8086_internal_MOV16(MMU_ptr(CPU_segment(CPU_SEGMENT_DS),CPU_readOPw()),AX);    //MOV [imm16], AX
}
void CPU8086_OPA4()
{
	CPU8086_internal_MOVSB();    //MOVSB
}
void CPU8086_OPA5()
{
	CPU8086_internal_MOVSW();    //MOVSW
}
void CPU8086_OPA6()
{
	CPU8086_internal_CMPSB();    //CMPSB
}
void CPU8086_OPA7()
{
	CPU8086_internal_CMPSW();    //CMPSW
}
void CPU8086_OPA8()
{
	CPU8086_internal_TEST8(AL,CPU_readOP());    //TEST AL,imm8
}
void CPU8086_OPA9()
{
	CPU8086_internal_TEST16(AX,CPU_readOPw());    //TEST AX,imm16
}
void CPU8086_OPAA()
{
	CPU8086_internal_STOSB();    //STOSB
}
void CPU8086_OPAB()
{
	CPU8086_internal_STOSW();    //STOSW
}
void CPU8086_OPAC()
{
	CPU8086_internal_LODSB();    //LODSB
}
void CPU8086_OPAD()
{
	CPU8086_internal_LODSW();    //LODSW
}
void CPU8086_OPAE()
{
	CPU8086_internal_SCASB();    //SCASB
}
void CPU8086_OPAF()
{
	CPU8086_internal_SCASW();    //SCASW
}
void CPU8086_OPB0()
{
	CPU8086_internal_MOV8(&AL,CPU_readOP());    //MOV AL,imm8
}
void CPU8086_OPB1()
{
	CPU8086_internal_MOV8(&CL,CPU_readOP());    //MOV CL,imm8
}
void CPU8086_OPB2()
{
	CPU8086_internal_MOV8(&DL,CPU_readOP());    //MOV DL,imm8
}
void CPU8086_OPB3()
{
	CPU8086_internal_MOV8(&BL,CPU_readOP());    //MOV BL,imm8
}
void CPU8086_OPB4()
{
	CPU8086_internal_MOV8(&AH,CPU_readOP());    //MOV AH,imm8
}
void CPU8086_OPB5()
{
	CPU8086_internal_MOV8(&CH,CPU_readOP());    //MOV CH,imm8
}
void CPU8086_OPB6()
{
	CPU8086_internal_MOV8(&DH,CPU_readOP());    //MOV DH,imm8
}
void CPU8086_OPB7()
{
	CPU8086_internal_MOV8(&BH,CPU_readOP());    //MOV BH,imm8
}
void CPU8086_OPB8()
{
	CPU8086_internal_MOV16(&AX,CPU_readOPw());    //MOV AX,imm16
}
void CPU8086_OPB9()
{
	CPU8086_internal_MOV16(&CX,CPU_readOPw());    //MOV CX,imm16
}
void CPU8086_OPBA()
{
	CPU8086_internal_MOV16(&DX,CPU_readOPw());    //MOV DX,imm16
}
void CPU8086_OPBB()
{
	CPU8086_internal_MOV16(&BX,CPU_readOPw());    //MOV BX,imm16
}
void CPU8086_OPBC()
{
	CPU8086_internal_MOV16(&SP,CPU_readOPw());    //MOV SP,imm16
}
void CPU8086_OPBD()
{
	CPU8086_internal_MOV16(&BP,CPU_readOPw());    //MOV BP,imm16
}
void CPU8086_OPBE()
{
	CPU8086_internal_MOV16(&SI,CPU_readOPw());    //MOV SI,imm16
}
void CPU8086_OPBF()
{
	CPU8086_internal_MOV16(&DI,CPU_readOPw());    //MOV DI,imm16
}
//So far, OK!
void CPU8086_OPC2()
{
	--CPU.calllayer;    //RET imm16 (Near return to calling proc and POP imm16 bytes)
	CPU_debugger_STOP();
	signed int popbytes = imm16();
	CPU8086_internal_RET(popbytes);
}
void CPU8086_OPC3()
{
	--CPU.calllayer;    //RET (Near return to calling proc)
	CPU_debugger_STOP();
	CPU8086_internal_RET(0);
}
void CPU8086_OPC4()
{
	MODRM_PARAMS params;    //LES Gv, Mp
	modrm_readparams(&params,2,0);
	unsigned int *reg;
	reg = modrm_addr_reg16(&params,1);
	*reg = MMU_rb(CPU_segment(CPU_SEGMENT_DS),getLEA(&params))|(MMU_rb(CPU_segment(CPU_SEGMENT_DS),getLEA(&params)+1)*256);
	ES = MMU_rb(CPU_segment(CPU_SEGMENT_DS),getLEA(&params)+2)|(MMU_rb(CPU_segment(CPU_SEGMENT_DS),getLEA(&params)+3)*256);
}
void CPU8086_OPC5()
{
	MODRM_PARAMS params;    //LDS Gv, Mp
	modrm_readparams(&params,2,0);
	unsigned int *reg;
	reg = modrm_addr_reg16(&params,1);
	*reg = MMU_rb(CPU_segment(CPU_SEGMENT_DS),getLEA(&params))|(MMU_rb(CPU_segment(CPU_SEGMENT_DS),getLEA(&params)+1)*256);
	DS = MMU_rb(CPU_segment(CPU_SEGMENT_DS),getLEA(&params)+2)|(MMU_rb(CPU_segment(CPU_SEGMENT_DS),getLEA(&params)+3)*256);
}
void CPU8086_OPC6()
{
	MODRM_PARAMS params;    //MOV modrm8,imm8
	modrm_readparams(&params,1,0);
	unsigned char val = CPU_readOP();
	modrm_write8(&params,2,val);
}
void CPU8086_OPC7()
{
	MODRM_PARAMS params;    //MOV modrm16,imm16
	modrm_readparams(&params,2,0);
	unsigned int val = CPU_readOPw();
	modrm_write16(&params,2,val);
}
void CPU8086_OPCA()
{
	--CPU.calllayer;    //RETF imm16 (Far return to calling proc and pop imm16 bytes)
	signed int popbytes = imm16();
	CPU8086_internal_RETF(popbytes);
}
void CPU8086_OPCB()
{
	if ((CPU.calllayer-1)<0)
	{
		/* Can't be in a simple program? */
	} --CPU.calllayer;    //RETF (Far return to calling proc)
	CPU8086_internal_RETF(0);
}
void CPU8086_OPCC()
{
	CPU8086_int(3);    //INT 3
}
void CPU8086_OPCD()
{
	CPU8086_int(CPU_readOP());    //INT imm8
}
void CPU8086_OPCE()
{
	CPU8086_internal_INTO();    //INTO
}
void CPU8086_OPCF()
{
	CPU8086_IRET();    //IRET : also restore interrupt flag!
}
void CPU8086_OPD4()
{
	CPU8086_internal_AAM(CPU_readOP());    //AAM
}
void CPU8086_OPD5()
{
	CPU8086_internal_AAD(CPU_readOP());    //AAD
}
void CPU8086_OPD7()
{
	CPU8086_internal_XLAT();    //XLAT
}
void CPU8086_OPE0()
{
	signed char rel8;    //LOOPNZ rel8
	rel8 = imm8();
	--CX;
	if ((CX) && !ZF)
	{
		IP += rel8;
	}
}
void CPU8086_OPE1()
{
	signed char rel8;    //LOOPZ rel8
	rel8 = imm8();
	--CX;
	if ((CX) && (ZF))
	{
		IP += rel8;
	}
}
void CPU8086_OPE2()
{
	signed char rel8;    //LOOP rel8
	rel8 = imm8();
	--CX;
	if (CX)
	{
		IP += rel8;
	}
}
void CPU8086_OPE3()
{
	signed char rel8;    //JCXZ rel8 : (CX=0)
	rel8 = imm8();
	if (!CX)
	{
		IP += rel8;
	}
}
void CPU8086_OPE4()
{
	AL = PORT_IN_B(CPU_readOP());     //IN AL,imm8
}
void CPU8086_OPE5()
{
	AX = PORT_IN_W(CPU_readOP());    //IN AX,imm8
}
void CPU8086_OPE6()
{
	PORT_OUT_B(CPU_readOP(),AL);     //OUT imm8,AL
}
void CPU8086_OPE7()
{
	PORT_OUT_W(CPU_readOP(),AX);    //OUT imm8,AX
}
void CPU8086_OPE8()
{
	++CPU.calllayer;    //CALL rel16
	signed int reloffset = imm16();
	CPU_PUSH16(&IP);
	IP += reloffset;
}
void CPU8086_OPE9()
{
	signed int reloffset = imm16();    //JMP imm16
	IP += reloffset;
}
void CPU8086_OPEA()
{
	unsigned int offset;    //JMP Ap
	offset = CPU_readOPw();
	unsigned int segment;
	segment = CPU_readOPw();
	CS = segment;
	IP = offset;
}
void CPU8086_OPEB()
{
	signed char reloffset = imm8();    //JMP imm8
	IP += reloffset;
}
void CPU8086_OPEC()
{
	AL = PORT_IN_B(DX);    //IN AL,DX
}
void CPU8086_OPED()
{
	AX = PORT_IN_W(DX);    //IN AX,DX
}
void CPU8086_OPEE()
{
	PORT_OUT_B(DX,AL);    //OUT DX,AL
}
void CPU8086_OPEF()
{
	PORT_OUT_W(DX,AX);    //OUT DX,AX
}
//Finally simply:
void CPU8086_OPF4()
{
	CPU.halt = 1;    //HLT : Wait for interrupt or 8087+ to occur!
}
void CPU8086_OPF5()
{
	if (!CF) CF = 1;    //CMC
	else CF = 0;
}
void CPU8086_OPF8()
{
	CF = 0;    //CLC
}
void CPU8086_OPF9()
{
	CF = 1;    //STC
}
void CPU8086_OPFA()
{
	IF = 0;    //CLI
}
void CPU8086_OPFB()
{
	IF = 1;    //STI
}
void CPU8086_OPFC()
{
	DF = 0;    //CLD
}
void CPU8086_OPFD()
{
	DF = 1;    //STD
}










/*

NOW COME THE GRP1-5 OPCODES:

*/

void CPU8086_OP80()
{
	MODRM_PARAMS params;
	modrm_readparams(&params,1,0);
	switch (MODRM_REG(params.modrm)) //What function?
	{
	case 0: //ADD
		CPU8086_internal_ADD8(modrm_addr8(&params,2),CPU_readOP()); //ADD Eb, Ib
		break;
	case 1: //OR
		CPU8086_internal_OR8(modrm_addr8(&params,2),CPU_readOP()); //OR Eb, Ib
		break;
	case 2: //ADC
		CPU8086_internal_ADC8(modrm_addr8(&params,2),CPU_readOP()); //ADC Eb, Ib
		break;
	case 3: //SBB
		CPU8086_internal_SBB8(modrm_addr8(&params,2),CPU_readOP()); //SBB Eb, Ib
		break;
	case 4: //AND
		CPU8086_internal_AND8(modrm_addr8(&params,2),CPU_readOP()); //AND Eb, Ib
		break;
	case 5: //SUB
		CPU8086_internal_SUB8(modrm_addr8(&params,2),-CPU_readOP()); //SUB Eb, Ib
		break;
	case 6: //XOR
		CPU8086_internal_XOR8(modrm_addr8(&params,2),CPU_readOP()); //XOR Eb, Ib
		break;
	case 7: //CMP
		CMP_b(*modrm_addr8(&params,2),CPU_readOP()); //CMP Eb, Ib
		break;
	default:
		break;
	}
}

void CPU8086_OP81() //GRP1 modrm(w),imm16
{
	MODRM_PARAMS params;
	modrm_readparams(&params,2,0);
	switch (MODRM_REG(params.modrm)) //What function?
	{
	case 0: //ADD
		CPU8086_internal_ADD16(modrm_addr16(&params,2),CPU_readOPw()); //ADD Eb, Ib
		break;
	case 1: //OR
		CPU8086_internal_OR16(modrm_addr16(&params,2),CPU_readOPw()); //OR Eb, Ib
		break;
	case 2: //ADC
		CPU8086_internal_ADC16(modrm_addr16(&params,2),CPU_readOPw()); //ADC Eb, Ib
		break;
	case 3: //SBB
		CPU8086_internal_SBB16(modrm_addr16(&params,2),CPU_readOPw()); //SBB Eb, Ib
		break;
	case 4: //AND
		CPU8086_internal_AND16(modrm_addr16(&params,2),CPU_readOPw()); //AND Eb, Ib
		break;
	case 5: //SUB
		CPU8086_internal_SUB16(modrm_addr16(&params,2),CPU_readOPw()); //SUB Eb, Ib
		break;
	case 6: //XOR
		CPU8086_internal_XOR16(modrm_addr16(&params,2),CPU_readOPw()); //XOR Eb, Ib
		break;
	case 7: //CMP
		CMP_w(*modrm_addr16(&params,2),CPU_readOPw()); //CMP Eb, Ib
		break;
	default:
		break;
	}
}

void CPU8086_OP82()
{
	CPU8086_OP80();    //Same!
}

void CPU8086_OP83() //GRP1 modrm16,imm8
{
	MODRM_PARAMS params;
	modrm_readparams(&params,2,0);
	switch (MODRM_REG(params.modrm)) //What function?
	{
	case 0: //ADD
		CPU8086_internal_ADD16(modrm_addr16(&params,2),unsigned2signed8(CPU_readOP())); //ADD Eb, Ib
		break;
	case 1: //OR
		CPU8086_internal_OR16(modrm_addr16(&params,2),unsigned2signed8(CPU_readOP())); //OR Eb, Ib
		break;
	case 2: //ADC
		CPU8086_internal_ADC16(modrm_addr16(&params,2),unsigned2signed8(CPU_readOP())); //ADC Eb, Ib
		break;
	case 3: //SBB
		CPU8086_internal_SBB16(modrm_addr16(&params,2),unsigned2signed8(CPU_readOP())); //SBB Eb, Ib
		break;
	case 4: //AND
		CPU8086_internal_AND16(modrm_addr16(&params,2),unsigned2signed8(CPU_readOP())); //AND Eb, Ib
		break;
	case 5: //SUB
		CPU8086_internal_SUB16(modrm_addr16(&params,2),unsigned2signed8(CPU_readOP())); //SUB Eb, Ib
		break;
	case 6: //XOR
		CPU8086_internal_XOR16(modrm_addr16(&params,2),unsigned2signed8(CPU_readOP())); //XOR Eb, Ib
		break;
	case 7: //CMP
		CMP_w(*modrm_addr16(&params,2),unsigned2signed8(CPU_readOP())); //CMP Eb, Ib
		break;
	default:
		break;
	}
}

void CPU8086_OPD0()
{
	MODRM_PARAMS params;
	modrm_readparams(&params,1,0);
	reg = MODRM_REG(params.modrm);
	oper1b = modrm_read8(&params,2);
	modrm_write8(&params,2,op_grp2_8(1));
}
void CPU8086_OPD1()
{
	MODRM_PARAMS params;
	modrm_readparams(&params,2,0);
	reg = MODRM_REG(params.modrm);
	oper1 = modrm_read16(&params,2);
	modrm_write16(&params,2,op_grp2_16(1));
}
void CPU8086_OPD2()
{
	MODRM_PARAMS params;
	modrm_readparams(&params,1,0);
	reg = MODRM_REG(params.modrm);
	oper1b = modrm_read8(&params,2);
	modrm_write8(&params,2,op_grp2_8(CL));
}
void CPU8086_OPD3()
{
	MODRM_PARAMS params;
	modrm_readparams(&params,2,0);
	reg = MODRM_REG(params.modrm);
	oper1 = modrm_read16(&params,2);
	modrm_write16(&params,2,op_grp2_16(CL));
}
void CPU8086_OPF6()
{
	MODRM_PARAMS params;
	modrm_readparams(&params,1,0);
	reg = MODRM_REG(params.modrm);
	oper1b = modrm_read8(&params,2);
	op_grp3_8();
	if ((MODRM_REG(params.modrm)>1) && (MODRM_REG(params.modrm)<4))
	{
		modrm_write8(&params,2,res8);
	}
}
void CPU8086_OPF7()
{
	MODRM_PARAMS params;
	modrm_readparams(&params,2,0);
	reg = MODRM_REG(params.modrm);
	oper1 = modrm_read16(&params,2);
	op_grp3_16();
	if ((MODRM_REG(params.modrm)>1) && (MODRM_REG(params.modrm)<4))
	{
		modrm_write16(&params,2,res16);
	}
}
//All OK up till here.
void CPU8086_OPFE()
{
	byte tempcf;
	MODRM_PARAMS params;
	modrm_readparams(&params,2,0);
	switch (MODRM_REG(params.modrm)) //What function?
	{
	case 0:
		tempcf = CF;
		res8 = modrm_read8(&params,2)+1;
		flag_add8(modrm_read8(&params,2),1);
		CF = tempcf;
		modrm_write8(&params,2,res8);
	case 1:
		tempcf = CF;
		res8 = modrm_read8(&params,2)-1;
		flag_sub8(modrm_read8(&params,2),1);
		CF = tempcf;
		modrm_write8(&params,2,res8);
	case 7: //---: Special: callback handler!
		CB_handler((byte)(CPU_readOPw()&0xFF)); //Call special handler!
	default: //Unknown opcode or special?
		break;
	}
}

extern word ea; //For GRP5 Opcode!
void CPU8086_OPFF()
{
	MODRM_PARAMS params;
	modrm_readparams(&params,2,0);
	reg = MODRM_REG(params.modrm);
	oper1 = modrm_read16(&params,2);
	ea = modrm_offset16(&params,2);
	op_grp5(modrm_addr16(&params,2));
}


































/*

Special stuff for NO COprocessor (8087)!

*/




void CPU8087_OPDBE3() //FNINIT
{
//Just continue like nothing happened!
}

void CPU8086_OPDB()
{
	unsigned char subOP = CPU_readOP(); //SubOP!
	unsigned int oldCS = 0;
	unsigned int oldIP = 0;
	oldCS = CS;
	oldIP = IP; //Save!
	if (subOP==0xE3) //FNINIT?
	{
		CPU8087_OPDBE3(); //Execute!
	}
	else
	{
		CS = oldCS;
		IP = oldIP; //Restore!
		CPU8086_noCOOP(); //Run error!
	}
}











void CPU8087_OPDFE0() //FNSTSW AX
{
//Just continue like nothing happened!
}

void CPU8086_OPDF()
{
	unsigned char subOP = CPU_readOP(); //SubOP!
	unsigned int oldCS = 0;
	unsigned int oldIP = 0;
	oldCS = CS;
	oldIP = IP; //Save!
	if (subOP==0xE0) //FNINIT?
	{
		CPU8087_OPDFE0(); //Execute!
	}
	else
	{
		CS = oldCS;
		IP = oldIP; //Restore!
		CPU8086_noCOOP(); //Run error!
	}
}

















void CPU8087_OPDDslash7()
{
//Just continue like nothing happened!
}

void CPU8086_OPDD() //For FPU!
{
	unsigned int oldCS = 0;
	unsigned int oldIP = 0;
	oldCS = CS;
	oldIP = IP; //Save!
	MODRM_PARAMS params;
	modrm_readparams(&params,1,0);
	if (MODRM_REG(params.modrm)==7) //Special?
	{
		CPU8087_OPDDslash7(); //Special!
	}
	else
	{
		CS = oldCS;
		IP = oldIP; //Restore!
		CPU8086_noCOOP(); //Error!
	}
}
















void CPU8087_OPD9slash7() //FNSTCW mem2i
{
//Just continue like nothing happened!
}

void CPU8086_OPD9() //For FPU!
{
	unsigned int oldCS = 0;
	unsigned int oldIP = 0;
	oldCS = CS;
	oldIP = IP; //Save!
	MODRM_PARAMS params;
	modrm_readparams(&params,1,0);
	if (MODRM_REG(params.modrm)==7) //Special?
	{
		CPU8087_OPD9slash7(); //Special!
	}
	else
	{
		CS = oldCS;
		IP = oldIP; //Restore!
		CPU8086_noCOOP(); //Error!
	}
}

inline void CPU8086_noCOOP() //Coprosessor opcodes handler!
{
	CPU8086_int(0x07); //Not present!
}