// license:BSD-3-Clause
// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett
static UINT8 I386OP(shift_rotate8)(i386_state *cpustate, UINT8 modrm, UINT32 value, UINT8 shift)
{
	UINT32 src = value & 0xff;
	UINT8 dst = value;

	if( shift == 0 ) {
		CYCLES_RM(cpustate,modrm, 3, 7);
	} else if( shift == 1 ) {
		switch( (modrm >> 3) & 0x7 )
		{
			case 0:         /* ROL rm8, 1 */
				cpustate->CF = (src & 0x80) ? 1 : 0;
				dst = (src << 1) + cpustate->CF;
				cpustate->OF = ((src ^ dst) & 0x80) ? 1 : 0;
				CYCLES_RM(cpustate,modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
				break;
			case 1:         /* ROR rm8, 1 */
				cpustate->CF = (src & 0x1) ? 1 : 0;
				dst = (cpustate->CF << 7) | (src >> 1);
				cpustate->OF = ((src ^ dst) & 0x80) ? 1 : 0;
				CYCLES_RM(cpustate,modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
				break;
			case 2:         /* RCL rm8, 1 */
				dst = (src << 1) + cpustate->CF;
				cpustate->CF = (src & 0x80) ? 1 : 0;
				cpustate->OF = ((src ^ dst) & 0x80) ? 1 : 0;
				CYCLES_RM(cpustate,modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
				break;
			case 3:         /* RCR rm8, 1 */
				dst = (cpustate->CF << 7) | (src >> 1);
				cpustate->CF = src & 0x1;
				cpustate->OF = ((src ^ dst) & 0x80) ? 1 : 0;
				CYCLES_RM(cpustate,modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
				break;
			case 4:         /* SHL/SAL rm8, 1 */
			case 6:
				dst = src << 1;
				cpustate->CF = (src & 0x80) ? 1 : 0;
				cpustate->OF = (((cpustate->CF << 7) ^ dst) & 0x80) ? 1 : 0;
				SetSZPF8(dst);
				CYCLES_RM(cpustate,modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
				break;
			case 5:         /* SHR rm8, 1 */
				dst = src >> 1;
				cpustate->CF = src & 0x1;
				cpustate->OF = (dst & 0x80) ? 1 : 0;
				SetSZPF8(dst);
				CYCLES_RM(cpustate,modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
				break;
			case 7:         /* SAR rm8, 1 */
				dst = (INT8)(src) >> 1;
				cpustate->CF = src & 0x1;
				cpustate->OF = 0;
				SetSZPF8(dst);
				CYCLES_RM(cpustate,modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
				break;
		}

	} else {
		switch( (modrm >> 3) & 0x7 )
		{
			case 0:         /* ROL rm8, i8 */
				if(!(shift & 7))
				{
					if(shift & 0x18)
					{
						cpustate->CF = src & 1;
						cpustate->OF = (src & 1) ^ ((src >> 7) & 1);
					}
					break;
				}
				shift &= 7;
				dst = ((src & ((UINT8)0xff >> shift)) << shift) |
						((src & ((UINT8)0xff << (8-shift))) >> (8-shift));
				cpustate->CF = dst & 0x1;
				cpustate->OF = (dst & 1) ^ (dst >> 7);
				CYCLES_RM(cpustate,modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
				break;
			case 1:         /* ROR rm8, i8 */
				if(!(shift & 7))
				{
					if(shift & 0x18)
					{
						cpustate->CF = (src >> 7) & 1;
						cpustate->OF = ((src >> 7) & 1) ^ ((src >> 6) & 1);
					}
					break;
				}
				shift &= 7;
				dst = ((src & ((UINT8)0xff << shift)) >> shift) |
						((src & ((UINT8)0xff >> (8-shift))) << (8-shift));
				cpustate->CF = (dst >> 7) & 1;
				cpustate->OF = ((dst >> 7) ^ (dst >> 6)) & 1;
				CYCLES_RM(cpustate,modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
				break;
			case 2:         /* RCL rm8, i8 */
				shift %= 9;
				dst = ((src & ((UINT8)0xff >> shift)) << shift) |
						((src & ((UINT8)0xff << (9-shift))) >> (9-shift)) |
						(cpustate->CF << (shift-1));
				if(shift) cpustate->CF = (src >> (8-shift)) & 0x1;
				cpustate->OF = cpustate->CF ^ ((dst >> 7) & 1);
				CYCLES_RM(cpustate,modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
				break;
			case 3:         /* RCR rm8, i8 */
				shift %= 9;
				dst = ((src & ((UINT8)0xff << shift)) >> shift) |
						((src & ((UINT8)0xff >> (8-shift))) << (9-shift)) |
						(cpustate->CF << (8-shift));
				if(shift) cpustate->CF = (src >> (shift-1)) & 0x1;
				cpustate->OF = ((dst >> 7) ^ (dst >> 6)) & 1;
				CYCLES_RM(cpustate,modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM);
				break;
			case 4:         /* SHL/SAL rm8, i8 */
			case 6:
				shift &= 31;
				dst = src << shift;
				cpustate->CF = (shift <= 8) && ((src >> (8 - shift)) & 1);
				SetSZPF8(dst);
				CYCLES_RM(cpustate,modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
				break;
			case 5:         /* SHR rm8, i8 */
				shift &= 31;
				dst = src >> shift;
				cpustate->CF = (src & (1 << (shift-1))) ? 1 : 0;
				SetSZPF8(dst);
				CYCLES_RM(cpustate,modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
				break;
			case 7:         /* SAR rm8, i8 */
				shift &= 31;
				dst = (INT8)src >> shift;
				cpustate->CF = (src & (1 << (shift-1))) ? 1 : 0;
				SetSZPF8(dst);
				CYCLES_RM(cpustate,modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM);
				break;
		}
	}

	return dst;
}



static void I386OP(adc_rm8_r8)(i386_state *cpustate)        // Opcode 0x10
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_REG8(modrm);
		dst = LOAD_RM8(modrm);
		dst = ADC8(cpustate, dst, src, cpustate->CF);
		STORE_RM8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		src = LOAD_REG8(modrm);
		dst = READ8(cpustate,ea);
		dst = ADC8(cpustate, dst, src, cpustate->CF);
		WRITE8(cpustate,ea, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_MEM);
	}
}

static void I386OP(adc_r8_rm8)(i386_state *cpustate)        // Opcode 0x12
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_RM8(modrm);
		dst = LOAD_REG8(modrm);
		dst = ADC8(cpustate, dst, src, cpustate->CF);
		STORE_REG8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,0,1);
		src = READ8(cpustate,ea);
		dst = LOAD_REG8(modrm);
		dst = ADC8(cpustate, dst, src, cpustate->CF);
		STORE_REG8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_MEM_REG);
	}
}

static void I386OP(adc_al_i8)(i386_state *cpustate)     // Opcode 0x14
{
	UINT8 src, dst;
	src = FETCH(cpustate);
	dst = REG8(AL);
	dst = ADC8(cpustate, dst, src, cpustate->CF);
	REG8(AL) = dst;
	CYCLES(cpustate,CYCLES_ALU_IMM_ACC);
}

static void I386OP(add_rm8_r8)(i386_state *cpustate)        // Opcode 0x00
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_REG8(modrm);
		dst = LOAD_RM8(modrm);
		dst = ADD8(cpustate,dst, src);
		STORE_RM8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		src = LOAD_REG8(modrm);
		dst = READ8(cpustate,ea);
		dst = ADD8(cpustate,dst, src);
		WRITE8(cpustate,ea, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_MEM);
	}
}

static void I386OP(add_r8_rm8)(i386_state *cpustate)        // Opcode 0x02
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_RM8(modrm);
		dst = LOAD_REG8(modrm);
		dst = ADD8(cpustate,dst, src);
		STORE_REG8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,0,1);
		src = READ8(cpustate,ea);
		dst = LOAD_REG8(modrm);
		dst = ADD8(cpustate,dst, src);
		STORE_REG8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_MEM_REG);
	}
}

static void I386OP(add_al_i8)(i386_state *cpustate)     // Opcode 0x04
{
	UINT8 src, dst;
	src = FETCH(cpustate);
	dst = REG8(AL);
	dst = ADD8(cpustate,dst, src);
	REG8(AL) = dst;
	CYCLES(cpustate,CYCLES_ALU_IMM_ACC);
}

static void I386OP(and_rm8_r8)(i386_state *cpustate)        // Opcode 0x20
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_REG8(modrm);
		dst = LOAD_RM8(modrm);
		dst = AND8(cpustate,dst, src);
		STORE_RM8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		src = LOAD_REG8(modrm);
		dst = READ8(cpustate,ea);
		dst = AND8(cpustate,dst, src);
		WRITE8(cpustate,ea, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_MEM);
	}
}

static void I386OP(and_r8_rm8)(i386_state *cpustate)        // Opcode 0x22
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_RM8(modrm);
		dst = LOAD_REG8(modrm);
		dst = AND8(cpustate,dst, src);
		STORE_REG8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,0,1);
		src = READ8(cpustate,ea);
		dst = LOAD_REG8(modrm);
		dst = AND8(cpustate,dst, src);
		STORE_REG8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_MEM_REG);
	}
}

static void I386OP(and_al_i8)(i386_state *cpustate)         // Opcode 0x24
{
	UINT8 src, dst;
	src = FETCH(cpustate);
	dst = REG8(AL);
	dst = AND8(cpustate,dst, src);
	REG8(AL) = dst;
	CYCLES(cpustate,CYCLES_ALU_IMM_ACC);
}

static void I386OP(clc)(i386_state *cpustate)               // Opcode 0xf8
{
	cpustate->CF = 0;
	CYCLES(cpustate,CYCLES_CLC);
}

static void I386OP(cld)(i386_state *cpustate)               // Opcode 0xfc
{
	cpustate->DF = 0;
	CYCLES(cpustate,CYCLES_CLD);
}

static void I386OP(cli)(i386_state *cpustate)               // Opcode 0xfa
{
	if(PROTECTED_MODE)
	{
		UINT8 IOPL = cpustate->IOP1 | (cpustate->IOP2 << 1);
		if(cpustate->CPL > IOPL) {
			logerror("Privilege error: I386OP(cli) CPL=%d IOPL=%d PC=%08X\n", cpustate->CPL, IOPL, cpustate->pc); 
			FAULT(FAULT_GP,0);
			//return;
		}
	}
	cpustate->IF = 0;
	CYCLES(cpustate,CYCLES_CLI);
}

static void I386OP(cmc)(i386_state *cpustate)               // Opcode 0xf5
{
	cpustate->CF ^= 1;
	CYCLES(cpustate,CYCLES_CMC);
}

static void I386OP(cmp_rm8_r8)(i386_state *cpustate)        // Opcode 0x38
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_REG8(modrm);
		dst = LOAD_RM8(modrm);
		SUB8(cpustate,dst, src);
		CYCLES(cpustate,CYCLES_CMP_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,0,1);
		src = LOAD_REG8(modrm);
		dst = READ8(cpustate,ea);
		SUB8(cpustate,dst, src);
		CYCLES(cpustate,CYCLES_CMP_REG_MEM);
	}
}

static void I386OP(cmp_r8_rm8)(i386_state *cpustate)        // Opcode 0x3a
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_RM8(modrm);
		dst = LOAD_REG8(modrm);
		SUB8(cpustate,dst, src);
		CYCLES(cpustate,CYCLES_CMP_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,0,1);
		src = READ8(cpustate,ea);
		dst = LOAD_REG8(modrm);
		SUB8(cpustate,dst, src);
		CYCLES(cpustate,CYCLES_CMP_MEM_REG);
	}
}

static void I386OP(cmp_al_i8)(i386_state *cpustate)         // Opcode 0x3c
{
	UINT8 src, dst;
	src = FETCH(cpustate);
	dst = REG8(AL);
	SUB8(cpustate,dst, src);
	CYCLES(cpustate,CYCLES_CMP_IMM_ACC);
}

static void I386OP(cmpsb)(i386_state *cpustate)             // Opcode 0xa6
{
	UINT32 eas, ead;
	UINT8 src, dst;
	if( cpustate->segment_prefix ) {
		eas = i386_translate(cpustate, cpustate->segment_override, cpustate->address_size ? REG32(ESI) : REG16(SI), 0, 1 );
	} else {
		eas = i386_translate(cpustate, DS, cpustate->address_size ? REG32(ESI) : REG16(SI), 0, 1 );
	}
	ead = i386_translate(cpustate, ES, cpustate->address_size ? REG32(EDI) : REG16(DI), 0, 1 );
	src = READ8(cpustate,eas);
	dst = READ8(cpustate,ead);
	SUB8(cpustate,src, dst);
	BUMP_SI(cpustate,1);
	BUMP_DI(cpustate,1);
	CYCLES(cpustate,CYCLES_CMPS);
}

static void I386OP(in_al_i8)(i386_state *cpustate)          // Opcode 0xe4
{
	UINT16 port = FETCH(cpustate);
	UINT8 data = READPORT8(cpustate, port);
	REG8(AL) = data;
	CYCLES(cpustate,CYCLES_IN_VAR);
}

static void I386OP(in_al_dx)(i386_state *cpustate)          // Opcode 0xec
{
	UINT16 port = REG16(DX);
	UINT8 data = READPORT8(cpustate, port);
	REG8(AL) = data;
	CYCLES(cpustate,CYCLES_IN);
}

static void I386OP(ja_rel8)(i386_state *cpustate)           // Opcode 0x77
{
	INT8 disp = FETCH(cpustate);
	if( cpustate->CF == 0 && cpustate->ZF == 0 ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jbe_rel8)(i386_state *cpustate)          // Opcode 0x76
{
	INT8 disp = FETCH(cpustate);
	if( cpustate->CF != 0 || cpustate->ZF != 0 ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jc_rel8)(i386_state *cpustate)           // Opcode 0x72
{
	INT8 disp = FETCH(cpustate);
	if( cpustate->CF != 0 ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jg_rel8)(i386_state *cpustate)           // Opcode 0x7f
{
	INT8 disp = FETCH(cpustate);
	if( cpustate->ZF == 0 && (cpustate->SF == cpustate->OF) ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jge_rel8)(i386_state *cpustate)          // Opcode 0x7d
{
	INT8 disp = FETCH(cpustate);
	if(cpustate->SF == cpustate->OF) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jl_rel8)(i386_state *cpustate)           // Opcode 0x7c
{
	INT8 disp = FETCH(cpustate);
	if( (cpustate->SF != cpustate->OF) ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jle_rel8)(i386_state *cpustate)      // Opcode 0x7e
{
	INT8 disp = FETCH(cpustate);
	if( cpustate->ZF != 0 || (cpustate->SF != cpustate->OF) ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jnc_rel8)(i386_state *cpustate)          // Opcode 0x73
{
	INT8 disp = FETCH(cpustate);
	if( cpustate->CF == 0 ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jno_rel8)(i386_state *cpustate)          // Opcode 0x71
{
	INT8 disp = FETCH(cpustate);
	if( cpustate->OF == 0 ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jnp_rel8)(i386_state *cpustate)          // Opcode 0x7b
{
	INT8 disp = FETCH(cpustate);
	if( cpustate->PF == 0 ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jns_rel8)(i386_state *cpustate)          // Opcode 0x79
{
	INT8 disp = FETCH(cpustate);
	if( cpustate->SF == 0 ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jnz_rel8)(i386_state *cpustate)          // Opcode 0x75
{
	INT8 disp = FETCH(cpustate);
	if( cpustate->ZF == 0 ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jo_rel8)(i386_state *cpustate)           // Opcode 0x70
{
	INT8 disp = FETCH(cpustate);
	if( cpustate->OF != 0 ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jp_rel8)(i386_state *cpustate)           // Opcode 0x7a
{
	INT8 disp = FETCH(cpustate);
	if( cpustate->PF != 0 ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(js_rel8)(i386_state *cpustate)           // Opcode 0x78
{
	INT8 disp = FETCH(cpustate);
	if( cpustate->SF != 0 ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jz_rel8)(i386_state *cpustate)           // Opcode 0x74
{
	INT8 disp = FETCH(cpustate);
	if( cpustate->ZF != 0 ) {
		NEAR_BRANCH(cpustate,disp);
		CYCLES(cpustate,CYCLES_JCC_DISP8);      /* TODO: Timing = 7 + m */
	} else {
		CYCLES(cpustate,CYCLES_JCC_DISP8_NOBRANCH);
	}
}

static void I386OP(jmp_rel8)(i386_state *cpustate)          // Opcode 0xeb
{
	INT8 disp = FETCH(cpustate);
	NEAR_BRANCH(cpustate,disp);
	CYCLES(cpustate,CYCLES_JMP_SHORT);      /* TODO: Timing = 7 + m */
}

static void I386OP(lahf)(i386_state *cpustate)              // Opcode 0x9f
{
	REG8(AH) = get_flags(cpustate) & 0xd7;
	CYCLES(cpustate,CYCLES_LAHF);
}

static void I386OP(lodsb)(i386_state *cpustate)             // Opcode 0xac
{
	UINT32 eas;
	if( cpustate->segment_prefix ) {
		eas = i386_translate(cpustate, cpustate->segment_override, cpustate->address_size ? REG32(ESI) : REG16(SI), 0, 1 );
	} else {
		eas = i386_translate(cpustate, DS, cpustate->address_size ? REG32(ESI) : REG16(SI), 0, 1 );
	}
	REG8(AL) = READ8(cpustate,eas);
	BUMP_SI(cpustate,1);
	CYCLES(cpustate,CYCLES_LODS);
}

static void I386OP(mov_rm8_r8)(i386_state *cpustate)        // Opcode 0x88
{
	UINT8 src;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_REG8(modrm);
		STORE_RM8(modrm, src);
		CYCLES(cpustate,CYCLES_MOV_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		src = LOAD_REG8(modrm);
		WRITE8(cpustate,ea, src);
		CYCLES(cpustate,CYCLES_MOV_REG_MEM);
	}
}

static void I386OP(mov_r8_rm8)(i386_state *cpustate)        // Opcode 0x8a
{
	UINT8 src;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_RM8(modrm);
		STORE_REG8(modrm, src);
		CYCLES(cpustate,CYCLES_MOV_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,0,1);
		src = READ8(cpustate,ea);
		STORE_REG8(modrm, src);
		CYCLES(cpustate,CYCLES_MOV_MEM_REG);
	}
}

static void I386OP(mov_rm8_i8)(i386_state *cpustate)        // Opcode 0xc6
{
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		UINT8 value = FETCH(cpustate);
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_MOV_IMM_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		UINT8 value = FETCH(cpustate);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_MOV_IMM_MEM);
	}
}
//#include "./i386ctrlregdefs.h"

static void I386OP(mov_r32_cr)(i386_state *cpustate)        // Opcode 0x0f 20
{
#if 1
	UINT32 oldpc = cpustate->prev_pc;
	if((PROTECTED_MODE && ((V8086_MODE) || (cpustate->CPL != 0)))) {
		logerror("Call from non-supervisor privilege: I386OP(mov_r32_cr) at %08X", oldpc); 
		FAULT(FAULT_GP, 0);
		//return;
	}
	UINT8 modrm = FETCH(cpustate);
	//if(modrm < 0xc0) {
	//	FAULT(FAULT_UD, 0);
	//	return;
	//}
	UINT8 IOPL = cpustate->IOP1 | (cpustate->IOP2 << 1);
	UINT8 cr = (modrm >> 3) & 0x7;
	//logdebug("MOV r32 CR%d VAL=(%08X)\n", cr, cpustate->cr[cr], oldpc);
//	if(cr < 5) {
//		if(cr == 1) {
//			FAULT(FAULT_UD, 0);
//			return;
//		}
		STORE_RM32(modrm, cpustate->cr[cr]);
		CYCLES(cpustate,CYCLES_MOV_CR_REG);
//	} else {
//		logerror("Index error");
//	}
#else
	if(PROTECTED_MODE && cpustate->CPL)
		FAULT(FAULT_GP, 0);
	uint8_t modrm = FETCH(cpustate);
	uint8_t cr = (modrm >> 3) & 0x7;

	STORE_RM32(modrm, cpustate->cr[cr]);
	CYCLES(cpustate, CYCLES_MOV_CR_REG);
#endif
}



#if 0
#include <execinfo.h>
#endif
void i386_change_protect_mode(i386_state *cpustate, int val)
{
//	logdebug("Change protect mode to %s\n", (val == 0) ? "NO" : "YES");
#if 0
	void *np[32]; 														
	int nptrs =backtrace(np, 32);										
	char **ss = backtrace_symbols(np, nptrs);							
	logdebug("Backtrace: \n");	\
	for(int __i = 0; __i < nptrs; __i++) {								
		logdebug("%s\n", ss[__i]);										
	}										
#endif
	cpustate->sreg[SS].d = 0;	
	cpustate->CPL = 0;
	if(val == 0) {
		cpustate->cr[0] = cpustate->cr[0] & ~0x1;
	} else {
		cpustate->cr[0] = cpustate->cr[0] | 0x1;
	}		
}

void i386_change_paging_mode(i386_state *cpustate, int val)
{
	// ToDo: Implement paging bit.
}

static void I386OP(mov_r32_dr)(i386_state *cpustate)        // Opcode 0x0f 21
{
	UINT8 modrm = FETCH(cpustate);
	if(modrm < 0xc0) {
		FAULT(FAULT_UD, 0);
		return;
	}
	if((PROTECTED_MODE && ((V8086_MODE) || (cpustate->CPL != 0)))) {
		logerror("Call from non-supervisor privilege: I386OP(mov_r32_dr)"); 
		FAULT(FAULT_GP, 0);
		return;
	}
	if((cpustate->dr[7] & I386_DR7_GD) != 0) {
		cpustate->dr[6] |= I386_DR6_BD;
		cpustate->dr[7] &= ~I386_DR7_GD;
		FAULT(FAULT_DB, 0);
	}
	UINT8 dr = (modrm >> 3) & 0x7;
	logdebug("MOV r32 DR%d VAL=(%08X)\n", dr, cpustate->dr[dr]);

	switch(dr)
	{
		case 0:
		case 1:
		case 2:
		case 3:
			STORE_RM32(modrm, cpustate->dr[dr]);
			CYCLES(cpustate,CYCLES_MOV_REG_DR0_3);
			break;
		case 4:
		case 6:
			STORE_RM32(modrm, ((cpustate->dr[6] & 0x0000f00f) | 0xfff0ff0));
			CYCLES(cpustate,CYCLES_MOV_REG_DR6_7);
			break;
		case 7:
			STORE_RM32(modrm, cpustate->dr[dr]);
			CYCLES(cpustate,CYCLES_MOV_REG_DR6_7);
			break;
		default:
			STORE_RM32(modrm, cpustate->dr[dr]);
			logerror("i386: mov_r32_dr illegal index \n", dr);
			return;
			break;
	}
}

static void I386OP(mov_cr_r32)(i386_state *cpustate)        // Opcode 0x0f 22
{
#if 1
	UINT32 oldpc = cpustate->prev_pc;
	if(PROTECTED_MODE && ((V8086_MODE) || (cpustate->CPL != 0))) {
		logerror("Call from non-supervisor privilege: I386OP(mov_cr_r32) at %08X", oldpc); 
		FAULT(FAULT_GP, 0);
		return;
	}
	UINT8 modrm = FETCH(cpustate);
	if(modrm < 0xc0) {
		FAULT(FAULT_UD, 0);
		return;
	}
	UINT8 IOPL = cpustate->IOP1 | (cpustate->IOP2 << 1);

	UINT8 cr = (modrm >> 3) & 0x7;
	UINT32 data = LOAD_RM32(modrm);
	UINT32 data_bak;
	//logdebug("MOV CR%d r32 VAL=(%08X) at %08X\n", cr, data, oldpc);
	switch(cr)
	{
		case 0:
			CYCLES(cpustate,CYCLES_MOV_REG_CR0);
			//if (PROTECTED_MODE != BIT(data, 0))
			//	debugger_privilege_hook();
			if((data & (I386_CR0_PE | I386_CR0_PG)) == (UINT32)I386_CR0_PG) {
				FAULT(FAULT_GP, 0);
			}
			if((data & (I386_CR0_NW | I386_CR0_CD)) == I386_CR0_NW) {
				FAULT(FAULT_GP, 0);
			}
#if 1
			data_bak = cpustate->cr[0];
			data &= I386_CR0_ALL;
			data &= ~I386_CR0_WP; // wp not supported on 386
			//logdebug("MOV CR0,xxxxh %08x -> %08x \n", data_bak, data);
			// ToDo: FPU
			//data |= I386_CR0_ET;	/* FPU present */
			//data &= ~I386_CR0_EM;
			data |= I386_CR0_EM | I386_CR0_NE;
			data &= ~(I386_CR0_MP | I386_CR0_ET);
//			//cpustate->cr[0] = data & ~(I386_CR0_PE | I386_CR0_PG);
#endif			
			cpustate->cr[0] = data;
#if 1
			if((data_bak & (I386_CR0_PE | I386_CR0_PG)) != (data & (I386_CR0_PE | I386_CR0_PG))) {
				// ToDo: TLB flush (paging)
				vtlb_flush_dynamic(cpustate->vtlb);
			}
			if((data_bak & I386_CR0_PE) != (data & I386_CR0_PE)) {
				if((data & I386_CR0_PE) != 0) {
					i386_change_protect_mode(cpustate, 1);
				}
			}
			if((data_bak & I386_CR0_PG) != (data & I386_CR0_PG)) {
				if((data & I386_CR0_PG) != 0) {
					cpustate->cr[0] |= I386_CR0_PG;
				} else {
					cpustate->cr[0] &= ~I386_CR0_PG;
				}
			}
			if((data_bak & I386_CR0_PE) != (data & I386_CR0_PE)) {
				if((data & I386_CR0_PE) == 0) {
					i386_change_protect_mode(cpustate, 0);
				}
			}
#endif
			return;
			break;
		case 1:
			FAULT(FAULT_UD, 0);
			return;
			break;

		case 2: CYCLES(cpustate,CYCLES_MOV_REG_CR2); break;
		case 3:
			CYCLES(cpustate,CYCLES_MOV_REG_CR3);
			vtlb_flush_dynamic(cpustate->vtlb);
			break;
		case 4:
			/*
			 * 10 = OSXMMEXCPT (support non masking exception by OS)
			 * 9 = OSFXSR (support FXSAVE, FXRSTOR by OS)
			 * 8 = PCE (performance monitoring counter enable)
			 * 7 = PGE (page global enable)
			 * 6 = MCE (machine check enable)
			 * 5 = PAE (physical address extention)
			 * 4 = PSE (page size extention)
			 * 3 = DE (debug extention)
			 * 2 = TSD (time stamp diable)
			 * 1 = PVI (protected mode virtual interrupt)
			 * 0 = VME (VM8086 mode extention)
			 */
			data_bak = 0x00000000; // ToDo: PGE
			if((data & ~data_bak) != 0) {
				if((data & I386_CR4_SET_MASK1) != 0) {
					FAULT(FAULT_GP, 0);
				}
				logerror("mov cr4 r32 : set 0x%08x\n", data);
			}
			data_bak = cpustate->cr[4];
			cpustate->cr[4] = data;
			if(((data ^ data_bak) & (I386_CR4_PSE | I386_CR4_PGE | I386_CR4_PAE)) != 0) { // PSE | PGE | PAE
				vtlb_flush_dynamic(cpustate->vtlb);
			}
			CYCLES(cpustate,1);
			return;
			break; // TODO
		default:
			logerror("i386: mov_cr_r32 CR%d!\n", cr);
			return;
	}
	cpustate->cr[cr] = data;
#else
	if((PROTECTED_MODE) && cpustate->CPL)
		FAULT(FAULT_GP, 0);
	uint8_t modrm = FETCH(cpustate);
	uint8_t cr = (modrm >> 3) & 0x7;
	uint32_t data = LOAD_RM32(modrm);
	switch(cr)
	{
		case 0:
			data &= 0xfffeffff; // wp not supported on 386
			CYCLES(cpustate, CYCLES_MOV_REG_CR0);
			//if (PROTECTED_MODE != BIT(data, 0))
			//	debugger_privilege_hook();
			break;
		case 2: CYCLES(cpustate, CYCLES_MOV_REG_CR2); break;
		case 3:
			CYCLES(cpustate, CYCLES_MOV_REG_CR3);
			vtlb_flush_dynamic(cpustate->vtlb);
			break;
	case 4: CYCLES(cpustate, 1); break; // TODO
		default:
			logerror("i386: mov_cr_r32 CR%d!\n", cr);
			return;
	}
	cpustate->cr[cr] = data;
#endif
}

static void I386OP(mov_dr_r32)(i386_state *cpustate)        // Opcode 0x0f 23
{
	UINT8 modrm = FETCH(cpustate);
	if(modrm < 0xc0) {
		FAULT(FAULT_UD, 0);
		return;
	}
	if((PROTECTED_MODE && ((V8086_MODE) || (cpustate->CPL != 0)))) {
		logerror("Call from non-supervisor privilege: I386OP(mov_dr_r32)"); 
		FAULT(FAULT_GP, 0);
		return;
	}
	if ((cpustate->dr[7] & I386_DR7_GD) != 0){
		cpustate->dr[6] |= I386_DR6_BD;
		cpustate->dr[7] &= ~I386_DR7_GD;
		FAULT(FAULT_DB, 0);
	}
	UINT8 dr = (modrm >> 3) & 0x7;
	UINT32 data =  LOAD_RM32(modrm);
	//logdebug("MOV DR%d r32 (VAL=%08X)\n", dr, data);

	switch(dr)
	{
		case 0:
		case 1:
		case 2:
		case 3:
			cpustate->dr[dr] = data;
			CYCLES(cpustate,CYCLES_MOV_DR0_3_REG);
			break;
		case 6:
			cpustate->dr[dr] =data;
			CYCLES(cpustate,CYCLES_MOV_DR6_7_REG);
			break;
		case 7:
			cpustate->dr[dr] = data;
			cpustate->reg.d[EBP] = 0;
			CYCLES(cpustate,CYCLES_MOV_DR6_7_REG);
			break;
		default:
			cpustate->dr[dr] = data;
			//logerror("i386: mov_dr_r32 DR%d!\n", dr);
			return;
	}
}

static void I386OP(mov_al_m8)(i386_state *cpustate)         // Opcode 0xa0
{
	UINT32 offset, ea;
	if( cpustate->address_size ) {
		offset = FETCH32(cpustate);
	} else {
		offset = FETCH16(cpustate);
	}
	/* TODO: Not sure if this is correct... */
	if( cpustate->segment_prefix ) {
		ea = i386_translate(cpustate, cpustate->segment_override, offset, 0, 1 );
	} else {
		ea = i386_translate(cpustate, DS, offset, 0, 1 );
	}
	REG8(AL) = READ8(cpustate,ea);
	CYCLES(cpustate,CYCLES_MOV_IMM_MEM);
}

static void I386OP(mov_m8_al)(i386_state *cpustate)         // Opcode 0xa2
{
	UINT32 offset, ea;
	if( cpustate->address_size ) {
		offset = FETCH32(cpustate);
	} else {
		offset = FETCH16(cpustate);
	}
	/* TODO: Not sure if this is correct... */
	if( cpustate->segment_prefix ) {
		ea = i386_translate(cpustate, cpustate->segment_override, offset, 1, 1 );
	} else {
		ea = i386_translate(cpustate, DS, offset, 1, 1 );
	}
	WRITE8(cpustate, ea, REG8(AL) );
	CYCLES(cpustate,CYCLES_MOV_MEM_ACC);
}

static void I386OP(mov_rm16_sreg)(i386_state *cpustate)     // Opcode 0x8c
{
	UINT8 modrm = FETCH(cpustate);
	int s = (modrm >> 3) & 0x7;

	if( modrm >= 0xc0 ) {
		if(cpustate->operand_size)
			STORE_RM32(modrm, cpustate->sreg[s].selector);
		else
			STORE_RM16(modrm, cpustate->sreg[s].selector);
		CYCLES(cpustate,CYCLES_MOV_SREG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,2);
		WRITE16(cpustate,ea, cpustate->sreg[s].selector);
		CYCLES(cpustate,CYCLES_MOV_SREG_MEM);
	}
}

static void I386OP(mov_sreg_rm16)(i386_state *cpustate)     // Opcode 0x8e
{
	UINT16 selector;
	UINT8 modrm = FETCH(cpustate);
	bool fault;
	int s = (modrm >> 3) & 0x7;

	if( modrm >= 0xc0 ) {
		selector = LOAD_RM16(modrm);
		CYCLES(cpustate,CYCLES_MOV_REG_SREG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,0,2);
		selector = READ16(cpustate,ea);
		CYCLES(cpustate,CYCLES_MOV_MEM_SREG);
	}

	i386_sreg_load(cpustate,selector,s,&fault);
	if((s == SS) && !fault)
	{
		if(cpustate->IF != 0) // if external interrupts are enabled
		{
			cpustate->IF = 0;  // reset IF for the next instruction
			cpustate->delayed_interrupt_enable = 1;
		}
	}
}

static void I386OP(mov_al_i8)(i386_state *cpustate)         // Opcode 0xb0
{
	REG8(AL) = FETCH(cpustate);
	CYCLES(cpustate,CYCLES_MOV_IMM_REG);
}

static void I386OP(mov_cl_i8)(i386_state *cpustate)         // Opcode 0xb1
{
	REG8(CL) = FETCH(cpustate);
	CYCLES(cpustate,CYCLES_MOV_IMM_REG);
}

static void I386OP(mov_dl_i8)(i386_state *cpustate)         // Opcode 0xb2
{
	REG8(DL) = FETCH(cpustate);
	CYCLES(cpustate,CYCLES_MOV_IMM_REG);
}

static void I386OP(mov_bl_i8)(i386_state *cpustate)         // Opcode 0xb3
{
	REG8(BL) = FETCH(cpustate);
	CYCLES(cpustate,CYCLES_MOV_IMM_REG);
}

static void I386OP(mov_ah_i8)(i386_state *cpustate)         // Opcode 0xb4
{
	REG8(AH) = FETCH(cpustate);
	CYCLES(cpustate,CYCLES_MOV_IMM_REG);
}

static void I386OP(mov_ch_i8)(i386_state *cpustate)         // Opcode 0xb5
{
	REG8(CH) = FETCH(cpustate);
	CYCLES(cpustate,CYCLES_MOV_IMM_REG);
}

static void I386OP(mov_dh_i8)(i386_state *cpustate)         // Opcode 0xb6
{
	REG8(DH) = FETCH(cpustate);
	CYCLES(cpustate,CYCLES_MOV_IMM_REG);
}

static void I386OP(mov_bh_i8)(i386_state *cpustate)         // Opcode 0xb7
{
	REG8(BH) = FETCH(cpustate);
	CYCLES(cpustate,CYCLES_MOV_IMM_REG);
}

static void I386OP(movsb)(i386_state *cpustate)             // Opcode 0xa4
{
	UINT32 eas, ead;
	UINT8 v;
	if( cpustate->segment_prefix ) {
		eas = i386_translate(cpustate, cpustate->segment_override, cpustate->address_size ? REG32(ESI) : REG16(SI), 0, 1 );
	} else {
		eas = i386_translate(cpustate, DS, cpustate->address_size ? REG32(ESI) : REG16(SI), 0, 1 );
	}
	ead = i386_translate(cpustate, ES, cpustate->address_size ? REG32(EDI) : REG16(DI), 1, 1 );
	v = READ8(cpustate,eas);
	WRITE8(cpustate,ead, v);
	BUMP_SI(cpustate,1);
	BUMP_DI(cpustate,1);
	CYCLES(cpustate,CYCLES_MOVS);
}

static void I386OP(or_rm8_r8)(i386_state *cpustate)         // Opcode 0x08
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_REG8(modrm);
		dst = LOAD_RM8(modrm);
		dst = OR8(cpustate,dst, src);
		STORE_RM8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		src = LOAD_REG8(modrm);
		dst = READ8(cpustate,ea);
		dst = OR8(cpustate,dst, src);
		WRITE8(cpustate,ea, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_MEM);
	}
}

static void I386OP(or_r8_rm8)(i386_state *cpustate)         // Opcode 0x0a
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_RM8(modrm);
		dst = LOAD_REG8(modrm);
		dst = OR8(cpustate,dst, src);
		STORE_REG8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,0,1);
		src = READ8(cpustate,ea);
		dst = LOAD_REG8(modrm);
		dst = OR8(cpustate,dst, src);
		STORE_REG8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_MEM_REG);
	}
}

static void I386OP(or_al_i8)(i386_state *cpustate)          // Opcode 0x0c
{
	UINT8 src, dst;
	src = FETCH(cpustate);
	dst = REG8(AL);
	dst = OR8(cpustate,dst, src);
	REG8(EAX) = dst;
	CYCLES(cpustate,CYCLES_ALU_IMM_ACC);
}

static void I386OP(out_al_i8)(i386_state *cpustate)         // Opcode 0xe6
{
	UINT16 port = FETCH(cpustate);
	UINT8 data = REG8(AL);
	WRITEPORT8(cpustate, port, data);
	CYCLES(cpustate,CYCLES_OUT_VAR);
}

static void I386OP(out_al_dx)(i386_state *cpustate)         // Opcode 0xee
{
	UINT16 port = REG16(DX);
	UINT8 data = REG8(AL);
	WRITEPORT8(cpustate, port, data);
	CYCLES(cpustate,CYCLES_OUT);
}


static void I386OP(arpl)(i386_state *cpustate)           // Opcode 0x63
{
	UINT16 src, dst;
	UINT8 modrm = FETCH(cpustate);
	UINT8 flag = 0;

	if(PROTECTED_MODE && !V8086_MODE)
	{
		if( modrm >= 0xc0 ) {
			src = LOAD_REG16(modrm);
			dst = LOAD_RM16(modrm);
			if( (dst&0x3) < (src&0x3) ) {
				dst = (dst&0xfffc) | (src&0x3);
				flag = 1;
				STORE_RM16(modrm, dst);
			}
		} else {
			UINT32 ea = GetEA(cpustate, modrm,1,2);
			src = LOAD_REG16(modrm);
			dst = READ16(cpustate, ea);
			if( (dst&0x3) < (src&0x3) ) {
				dst = (dst&0xfffc) | (src&0x3);
				flag = 1;
				WRITE16(cpustate, ea, dst);
			}
		}
		SetZF(flag);
	}
	else {
		report_invalid_opcode(cpustate);
		i386_trap(cpustate, 6, 0, 0);  // invalid opcode in real mode or v8086 mode
	}
}

static void I386OP(push_i8)(i386_state *cpustate)           // Opcode 0x6a
{
	UINT8 value = FETCH(cpustate);
	PUSH8(cpustate,value);
	CYCLES(cpustate,CYCLES_PUSH_IMM);
}

static void I386OP(ins_generic)(i386_state *cpustate, int size)
{
	UINT32 ead;
	UINT8 vb;
	UINT16 vw;
	UINT32 vd;

	ead = i386_translate(cpustate, ES, cpustate->address_size ? REG32(EDI) : REG16(DI), 1, size);

	switch(size) {
	case 1:
		vb = READPORT8(cpustate, REG16(DX));
		WRITE8(cpustate,ead, vb);
		break;
	case 2:
		vw = READPORT16(cpustate, REG16(DX));
		WRITE16(cpustate,ead, vw);
		break;
	case 4:
		vd = READPORT32(cpustate, REG16(DX));
		WRITE32(cpustate,ead, vd);
		break;
	}

	if(cpustate->address_size)
		REG32(EDI) += ((cpustate->DF) ? -1 : 1) * size;
	else
		REG16(DI) += ((cpustate->DF) ? -1 : 1) * size;
	CYCLES(cpustate,CYCLES_INS);    // TODO: Confirm this value
}

static void I386OP(insb)(i386_state *cpustate)              // Opcode 0x6c
{
	I386OP(ins_generic)(cpustate, 1);
}

static void I386OP(insw)(i386_state *cpustate)              // Opcode 0x6d
{
	I386OP(ins_generic)(cpustate, 2);
}

static void I386OP(insd)(i386_state *cpustate)              // Opcode 0x6d
{
	I386OP(ins_generic)(cpustate, 4);
}

static void I386OP(outs_generic)(i386_state *cpustate, int size)
{
	UINT32 eas;
	UINT8 vb;
	UINT16 vw;
	UINT32 vd;

	if( cpustate->segment_prefix ) {
		eas = i386_translate(cpustate, cpustate->segment_override, cpustate->address_size ? REG32(ESI) : REG16(SI), 0, size );
	} else {
		eas = i386_translate(cpustate, DS, cpustate->address_size ? REG32(ESI) : REG16(SI), 0, size );
	}

	switch(size) {
	case 1:
		vb = READ8(cpustate,eas);
		WRITEPORT8(cpustate, REG16(DX), vb);
		break;
	case 2:
		vw = READ16(cpustate,eas);
		WRITEPORT16(cpustate, REG16(DX), vw);
		break;
	case 4:
		vd = READ32(cpustate,eas);
		WRITEPORT32(cpustate, REG16(DX), vd);
		break;
	}

	if(cpustate->address_size)
		REG32(ESI) += ((cpustate->DF) ? -1 : 1) * size;
	else
		REG16(SI) += ((cpustate->DF) ? -1 : 1) * size;
	CYCLES(cpustate,CYCLES_OUTS);   // TODO: Confirm this value
}

static void I386OP(outsb)(i386_state *cpustate)             // Opcode 0x6e
{
	I386OP(outs_generic)(cpustate, 1);
}

static void I386OP(outsw)(i386_state *cpustate)             // Opcode 0x6f
{
	I386OP(outs_generic)(cpustate, 2);
}

static void I386OP(outsd)(i386_state *cpustate)             // Opcode 0x6f
{
	I386OP(outs_generic)(cpustate, 4);
}

static void I386OP(repeat)(i386_state *cpustate, int invert_flag)
{
	UINT32 repeated_eip = cpustate->eip;
	UINT32 repeated_pc = cpustate->pc;
	UINT8 opcode; // = FETCH(cpustate);
//  UINT32 eas, ead;
	UINT32 count;
	INT32 cycle_base = 0, cycle_adjustment = 0;
	UINT8 prefix_flag=1;
	UINT8 *flag = NULL;


	do {
	repeated_eip = cpustate->eip;
	repeated_pc = cpustate->pc;
	opcode = FETCH(cpustate);
	switch(opcode) {
		case 0x0f:
		if (invert_flag == 0)
			I386OP(decode_three_bytef3)(cpustate); // sse f3 0f
		else
			I386OP(decode_three_bytef2)(cpustate); // sse f2 0f
		return;
		case 0x26:
		cpustate->segment_override=ES;
		cpustate->segment_prefix=1;
		break;
		case 0x2e:
		cpustate->segment_override=CS;
		cpustate->segment_prefix=1;
		break;
		case 0x36:
		cpustate->segment_override=SS;
		cpustate->segment_prefix=1;
		break;
		case 0x3e:
		cpustate->segment_override=DS;
		cpustate->segment_prefix=1;
		break;
		case 0x64:
		cpustate->segment_override=FS;
		cpustate->segment_prefix=1;
		break;
		case 0x65:
		cpustate->segment_override=GS;
		cpustate->segment_prefix=1;
		break;
		case 0x66:
		cpustate->operand_size ^= 1;
		cpustate->xmm_operand_size ^= 1;
		break;
		case 0x67:
		cpustate->address_size ^= 1;
		break;
		default:
		prefix_flag=0;
	}
	} while (prefix_flag);


	if( cpustate->segment_prefix ) {
		// FIXME: the following does not work if both address override and segment override are used
		i386_translate(cpustate, cpustate->segment_override, cpustate->sreg[cpustate->segment_prefix].d ? REG32(ESI) : REG16(SI), -1, 1 );
	} else {
		//eas =
		i386_translate(cpustate, DS, cpustate->address_size ? REG32(ESI) : REG16(SI), -1, 1 );
	}
	i386_translate(cpustate, ES, cpustate->address_size ? REG32(EDI) : REG16(DI), -1, 1 );

	switch(opcode)
	{
		case 0x6c:
		case 0x6d:
			/* INSB, INSW, INSD */
			// TODO: cycle count
			cycle_base = 8;
			cycle_adjustment = -4;
			flag = NULL;
			break;

		case 0x6e:
		case 0x6f:
			/* OUTSB, OUTSW, OUTSD */
			// TODO: cycle count
			cycle_base = 8;
			cycle_adjustment = -4;
			flag = NULL;
			break;

		case 0xa4:
		case 0xa5:
			/* MOVSB, MOVSW, MOVSD */
			cycle_base = 8;
			cycle_adjustment = -4;
			flag = NULL;
			break;

		case 0xa6:
		case 0xa7:
			/* CMPSB, CMPSW, CMPSD */
			cycle_base = 5;
			cycle_adjustment = -1;
			flag = &cpustate->ZF;
			break;

		case 0xac:
		case 0xad:
			/* LODSB, LODSW, LODSD */
			cycle_base = 5;
			cycle_adjustment = 1;
			flag = NULL;
			break;

		case 0xaa:
		case 0xab:
			/* STOSB, STOSW, STOSD */
			cycle_base = 5;
			cycle_adjustment = 0;
			flag = NULL;
			break;

		case 0xae:
		case 0xaf:
			/* SCASB, SCASW, SCASD */
			cycle_base = 5;
			cycle_adjustment = 0;
			flag = &cpustate->ZF;
			break;

		case 0x90:
			CYCLES(cpustate,CYCLES_NOP);
			return;

		case 0xc2: // sigh
		case 0xc3:
			cpustate->pc--;
			return;

		default:
			logerror("i386: Invalid REP/opcode %02X combination at %08x\n",opcode, cpustate->pc - 2);
			cpustate->pc--;
			break;
	}

	if( cpustate->address_size ) {
		if( REG32(ECX) == 0 )
			return;
	} else {
		if( REG16(CX) == 0 )
			return;
	}

	/* now actually perform the repeat */
	CYCLES_NUM(cycle_base);
	do
	{
		cpustate->eip = repeated_eip;
		cpustate->pc = repeated_pc;
		try
		{
			I386OP(decode_opcode)(cpustate);
		}
		catch (UINT64 e)
		{
			cpustate->eip = cpustate->prev_eip;
			logerror("THROWN at I386_OP(repeat)() line %d\n", __LINE__);
			throw e;
		}

		CYCLES_NUM(cycle_adjustment);

		if (cpustate->address_size)
			count = --REG32(ECX);
		else
			count = --REG16(CX);
		if (cpustate->cycles <= 0)
			goto outofcycles;
	}
	while( count && (!flag || (invert_flag ? !*flag : *flag)) );
	return;

outofcycles:
	/* if we run out of cycles to execute, and we are still in the repeat, we need
	 * to exit this instruction in such a way to go right back into it when we have
	 * time to execute cycles */
	if(flag && (invert_flag ? *flag : !*flag))
		return;
	cpustate->eip = cpustate->prev_eip;
	CHANGE_PC(cpustate,cpustate->eip);
	CYCLES_NUM(-cycle_base);
}

static void I386OP(rep)(i386_state *cpustate)               // Opcode 0xf3
{
	I386OP(repeat)(cpustate, 0);
}

static void I386OP(repne)(i386_state *cpustate)             // Opcode 0xf2
{
	I386OP(repeat)(cpustate, 1);
}

static void I386OP(sahf)(i386_state *cpustate)              // Opcode 0x9e
{
	set_flags(cpustate, (get_flags(cpustate) & 0xffffff00) | (REG8(AH) & 0xd7) );
	CYCLES(cpustate,CYCLES_SAHF);
}

static void I386OP(sbb_rm8_r8)(i386_state *cpustate)        // Opcode 0x18
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_REG8(modrm);
		dst = LOAD_RM8(modrm);
		dst = SBB8(cpustate, dst, src, cpustate->CF);
		STORE_RM8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		src = LOAD_REG8(modrm);
		dst = READ8(cpustate,ea);
		dst = SBB8(cpustate, dst, src, cpustate->CF);
		WRITE8(cpustate,ea, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_MEM);
	}
}

static void I386OP(sbb_r8_rm8)(i386_state *cpustate)        // Opcode 0x1a
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_RM8(modrm);
		dst = LOAD_REG8(modrm);
		dst = SBB8(cpustate, dst, src, cpustate->CF);
		STORE_REG8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,0,1);
		src = READ8(cpustate,ea);
		dst = LOAD_REG8(modrm);
		dst = SBB8(cpustate, dst, src, cpustate->CF);
		STORE_REG8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_MEM_REG);
	}
}

static void I386OP(sbb_al_i8)(i386_state *cpustate)         // Opcode 0x1c
{
	UINT8 src, dst;
	src = FETCH(cpustate);
	dst = REG8(AL);
	dst = SBB8(cpustate, dst, src, cpustate->CF);
	REG8(EAX) = dst;
	CYCLES(cpustate,CYCLES_ALU_IMM_ACC);
}

static void I386OP(scasb)(i386_state *cpustate)             // Opcode 0xae
{
	UINT32 eas;
	UINT8 src, dst;
	eas = i386_translate(cpustate, ES, cpustate->address_size ? REG32(EDI) : REG16(DI), 0, 1 );
	src = READ8(cpustate,eas);
	dst = REG8(AL);
	SUB8(cpustate,dst, src);
	BUMP_DI(cpustate,1);
	CYCLES(cpustate,CYCLES_SCAS);
}

static void I386OP(setalc)(i386_state *cpustate)            // Opcode 0xd6 (undocumented)
{
	if( cpustate->CF ) {
		REG8(AL) = 0xff;
	} else {
		REG8(AL) = 0;
	}
	CYCLES(cpustate,3);
}

static void I386OP(seta_rm8)(i386_state *cpustate)          // Opcode 0x0f 97
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->CF == 0 && cpustate->ZF == 0 ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(setbe_rm8)(i386_state *cpustate)         // Opcode 0x0f 96
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->CF != 0 || cpustate->ZF != 0 ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(setc_rm8)(i386_state *cpustate)          // Opcode 0x0f 92
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->CF != 0 ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(setg_rm8)(i386_state *cpustate)          // Opcode 0x0f 9f
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->ZF == 0 && (cpustate->SF == cpustate->OF) ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(setge_rm8)(i386_state *cpustate)         // Opcode 0x0f 9d
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if(cpustate->SF == cpustate->OF) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(setl_rm8)(i386_state *cpustate)          // Opcode 0x0f 9c
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->SF != cpustate->OF ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(setle_rm8)(i386_state *cpustate)         // Opcode 0x0f 9e
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->ZF != 0 || (cpustate->SF != cpustate->OF) ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(setnc_rm8)(i386_state *cpustate)         // Opcode 0x0f 93
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->CF == 0 ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(setno_rm8)(i386_state *cpustate)         // Opcode 0x0f 91
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->OF == 0 ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(setnp_rm8)(i386_state *cpustate)         // Opcode 0x0f 9b
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->PF == 0 ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(setns_rm8)(i386_state *cpustate)         // Opcode 0x0f 99
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->SF == 0 ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(setnz_rm8)(i386_state *cpustate)         // Opcode 0x0f 95
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->ZF == 0 ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(seto_rm8)(i386_state *cpustate)          // Opcode 0x0f 90
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->OF != 0 ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(setp_rm8)(i386_state *cpustate)          // Opcode 0x0f 9a
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->PF != 0 ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(sets_rm8)(i386_state *cpustate)          // Opcode 0x0f 98
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->SF != 0 ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(setz_rm8)(i386_state *cpustate)          // Opcode 0x0f 94
{
	UINT8 modrm = FETCH(cpustate);
	UINT8 value = 0;
	if( cpustate->ZF != 0 ) {
		value = 1;
	}
	if( modrm >= 0xc0 ) {
		STORE_RM8(modrm, value);
		CYCLES(cpustate,CYCLES_SETCC_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		WRITE8(cpustate,ea, value);
		CYCLES(cpustate,CYCLES_SETCC_MEM);
	}
}

static void I386OP(stc)(i386_state *cpustate)               // Opcode 0xf9
{
	cpustate->CF = 1;
	CYCLES(cpustate,CYCLES_STC);
}

static void I386OP(std)(i386_state *cpustate)               // Opcode 0xfd
{
	cpustate->DF = 1;
	CYCLES(cpustate,CYCLES_STD);
}

static void I386OP(sti)(i386_state *cpustate)               // Opcode 0xfb
{
	if(PROTECTED_MODE)
	{
		UINT8 IOPL = cpustate->IOP1 | (cpustate->IOP2 << 1);
		if(cpustate->CPL > IOPL) {
			logerror("Privilege error: I386OP(sti) CPL=%d IOPL=%d\n", cpustate->CPL, IOPL); 
			FAULT(FAULT_GP,0);
			//return;
		}
	}
	cpustate->delayed_interrupt_enable = 1;  // IF is set after the next instruction.
	CYCLES(cpustate,CYCLES_STI);
}

static void I386OP(stosb)(i386_state *cpustate)             // Opcode 0xaa
{
	UINT32 ead;
	ead = i386_translate(cpustate, ES, cpustate->address_size ? REG32(EDI) : REG16(DI), 1, 1 );
	WRITE8(cpustate,ead, REG8(AL));
	BUMP_DI(cpustate,1);
	CYCLES(cpustate,CYCLES_STOS);
}

static void I386OP(sub_rm8_r8)(i386_state *cpustate)        // Opcode 0x28
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_REG8(modrm);
		dst = LOAD_RM8(modrm);
		dst = SUB8(cpustate,dst, src);
		STORE_RM8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		src = LOAD_REG8(modrm);
		dst = READ8(cpustate,ea);
		dst = SUB8(cpustate,dst, src);
		WRITE8(cpustate,ea, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_MEM);
	}
}

static void I386OP(sub_r8_rm8)(i386_state *cpustate)        // Opcode 0x2a
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_RM8(modrm);
		dst = LOAD_REG8(modrm);
		dst = SUB8(cpustate,dst, src);
		STORE_REG8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,0,1);
		src = READ8(cpustate,ea);
		dst = LOAD_REG8(modrm);
		dst = SUB8(cpustate,dst, src);
		STORE_REG8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_MEM_REG);
	}
}

static void I386OP(sub_al_i8)(i386_state *cpustate)         // Opcode 0x2c
{
	UINT8 src, dst;
	src = FETCH(cpustate);
	dst = REG8(EAX);
	dst = SUB8(cpustate,dst, src);
	REG8(EAX) = dst;
	CYCLES(cpustate,CYCLES_ALU_IMM_ACC);
}

static void I386OP(test_al_i8)(i386_state *cpustate)        // Opcode 0xa8
{
	UINT8 src = FETCH(cpustate);
	UINT8 dst = REG8(AL);
	dst = src & dst;
	SetSZPF8(dst);
	cpustate->CF = 0;
	cpustate->OF = 0;
	CYCLES(cpustate,CYCLES_ALU_IMM_ACC);
}

static void I386OP(test_rm8_r8)(i386_state *cpustate)       // Opcode 0x84
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_REG8(modrm);
		dst = LOAD_RM8(modrm);
		dst = src & dst;
		SetSZPF8(dst);
		cpustate->CF = 0;
		cpustate->OF = 0;
		CYCLES(cpustate,CYCLES_TEST_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,0,1);
		src = LOAD_REG8(modrm);
		dst = READ8(cpustate,ea);
		dst = src & dst;
		SetSZPF8(dst);
		cpustate->CF = 0;
		cpustate->OF = 0;
		CYCLES(cpustate,CYCLES_TEST_REG_MEM);
	}
}

static void I386OP(xchg_r8_rm8)(i386_state *cpustate)       // Opcode 0x86
{
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		UINT8 src = LOAD_RM8(modrm);
		UINT8 dst = LOAD_REG8(modrm);
		STORE_REG8(modrm, src);
		STORE_RM8(modrm, dst);
		CYCLES(cpustate,CYCLES_XCHG_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		UINT8 src = READ8(cpustate,ea);
		UINT8 dst = LOAD_REG8(modrm);
		WRITE8(cpustate,ea, dst);
		STORE_REG8(modrm, src);
		CYCLES(cpustate,CYCLES_XCHG_REG_MEM);
	}
}

static void I386OP(xor_rm8_r8)(i386_state *cpustate)        // Opcode 0x30
{
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_REG8(modrm);
		dst = LOAD_RM8(modrm);
		dst = XOR8(cpustate,dst, src);
		STORE_RM8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		src = LOAD_REG8(modrm);
		dst = READ8(cpustate,ea);
		dst = XOR8(cpustate,dst, src);
		WRITE8(cpustate,ea, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_MEM);
	}
}

static void I386OP(xor_r8_rm8)(i386_state *cpustate)        // Opcode 0x32
{
	UINT32 src, dst;
	UINT8 modrm = FETCH(cpustate);
	if( modrm >= 0xc0 ) {
		src = LOAD_RM8(modrm);
		dst = LOAD_REG8(modrm);
		dst = XOR8(cpustate,dst, src);
		STORE_REG8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_REG_REG);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,0,1);
		src = READ8(cpustate,ea);
		dst = LOAD_REG8(modrm);
		dst = XOR8(cpustate,dst, src);
		STORE_REG8(modrm, dst);
		CYCLES(cpustate,CYCLES_ALU_MEM_REG);
	}
}

static void I386OP(xor_al_i8)(i386_state *cpustate)         // Opcode 0x34
{
	UINT8 src, dst;
	src = FETCH(cpustate);
	dst = REG8(AL);
	dst = XOR8(cpustate,dst, src);
	REG8(AL) = dst;
	CYCLES(cpustate,CYCLES_ALU_IMM_ACC);
}



static void I386OP(group80_8)(i386_state *cpustate)         // Opcode 0x80
{
	UINT32 ea;
	UINT8 src, dst;
	UINT8 modrm = FETCH(cpustate);

	switch( (modrm >> 3) & 0x7 )
	{
		case 0:     // ADD Rm8, i8
			if( modrm >= 0xc0 ) {
				dst = LOAD_RM8(modrm);
				src = FETCH(cpustate);
				dst = ADD8(cpustate,dst, src);
				STORE_RM8(modrm, dst);
				CYCLES(cpustate,CYCLES_ALU_REG_REG);
			} else {
				ea = GetEA(cpustate,modrm,0,1);
				dst = READ8(cpustate,ea);
				src = FETCH(cpustate);
				dst = ADD8(cpustate,dst, src);
				WRITE8(cpustate,ea, dst);
				CYCLES(cpustate,CYCLES_ALU_REG_MEM);
			}
			break;
		case 1:     // OR Rm8, i8
			if( modrm >= 0xc0 ) {
				dst = LOAD_RM8(modrm);
				src = FETCH(cpustate);
				dst = OR8(cpustate,dst, src);
				STORE_RM8(modrm, dst);
				CYCLES(cpustate,CYCLES_ALU_REG_REG);
			} else {
				ea = GetEA(cpustate,modrm,1,1);
				dst = READ8(cpustate,ea);
				src = FETCH(cpustate);
				dst = OR8(cpustate,dst, src);
				WRITE8(cpustate,ea, dst);
				CYCLES(cpustate,CYCLES_ALU_REG_MEM);
			}
			break;
		case 2:     // ADC Rm8, i8
			if( modrm >= 0xc0 ) {
				dst = LOAD_RM8(modrm);
				src = FETCH(cpustate);
				dst = ADC8(cpustate, dst, src, cpustate->CF);
				STORE_RM8(modrm, dst);
				CYCLES(cpustate,CYCLES_ALU_REG_REG);
			} else {
				ea = GetEA(cpustate,modrm,1,1);
				dst = READ8(cpustate,ea);
				src = FETCH(cpustate);
				dst = ADC8(cpustate, dst, src, cpustate->CF);
				WRITE8(cpustate,ea, dst);
				CYCLES(cpustate,CYCLES_ALU_REG_MEM);
			}
			break;
		case 3:     // SBB Rm8, i8
			if( modrm >= 0xc0 ) {
				dst = LOAD_RM8(modrm);
				src = FETCH(cpustate);
				dst = SBB8(cpustate, dst, src, cpustate->CF);
				STORE_RM8(modrm, dst);
				CYCLES(cpustate,CYCLES_ALU_REG_REG);
			} else {
				ea = GetEA(cpustate,modrm,1,1);
				dst = READ8(cpustate,ea);
				src = FETCH(cpustate);
				dst = SBB8(cpustate, dst, src, cpustate->CF);
				WRITE8(cpustate,ea, dst);
				CYCLES(cpustate,CYCLES_ALU_REG_MEM);
			}
			break;
		case 4:     // AND Rm8, i8
			if( modrm >= 0xc0 ) {
				dst = LOAD_RM8(modrm);
				src = FETCH(cpustate);
				dst = AND8(cpustate,dst, src);
				STORE_RM8(modrm, dst);
				CYCLES(cpustate,CYCLES_ALU_REG_REG);
			} else {
				ea = GetEA(cpustate,modrm,1,1);
				dst = READ8(cpustate,ea);
				src = FETCH(cpustate);
				dst = AND8(cpustate,dst, src);
				WRITE8(cpustate,ea, dst);
				CYCLES(cpustate,CYCLES_ALU_REG_MEM);
			}
			break;
		case 5:     // SUB Rm8, i8
			if( modrm >= 0xc0 ) {
				dst = LOAD_RM8(modrm);
				src = FETCH(cpustate);
				dst = SUB8(cpustate,dst, src);
				STORE_RM8(modrm, dst);
				CYCLES(cpustate,CYCLES_ALU_REG_REG);
			} else {
				ea = GetEA(cpustate,modrm,1,1);
				dst = READ8(cpustate,ea);
				src = FETCH(cpustate);
				dst = SUB8(cpustate,dst, src);
				WRITE8(cpustate,ea, dst);
				CYCLES(cpustate,CYCLES_ALU_REG_MEM);
			}
			break;
		case 6:     // XOR Rm8, i8
			if( modrm >= 0xc0 ) {
				dst = LOAD_RM8(modrm);
				src = FETCH(cpustate);
				dst = XOR8(cpustate,dst, src);
				STORE_RM8(modrm, dst);
				CYCLES(cpustate,CYCLES_ALU_REG_REG);
			} else {
				ea = GetEA(cpustate,modrm,1,1);
				dst = READ8(cpustate,ea);
				src = FETCH(cpustate);
				dst = XOR8(cpustate,dst, src);
				WRITE8(cpustate,ea, dst);
				CYCLES(cpustate,CYCLES_ALU_REG_MEM);
			}
			break;
		case 7:     // CMP Rm8, i8
			if( modrm >= 0xc0 ) {
				dst = LOAD_RM8(modrm);
				src = FETCH(cpustate);
				SUB8(cpustate,dst, src);
				CYCLES(cpustate,CYCLES_CMP_REG_REG);
			} else {
				ea = GetEA(cpustate,modrm,0,1);
				dst = READ8(cpustate,ea);
				src = FETCH(cpustate);
				SUB8(cpustate,dst, src);
				CYCLES(cpustate,CYCLES_CMP_REG_MEM);
			}
			break;
	}
}

static void I386OP(groupC0_8)(i386_state *cpustate)         // Opcode 0xc0
{
	UINT8 dst;
	UINT8 modrm = FETCH(cpustate);
	UINT8 shift;

	if( modrm >= 0xc0 ) {
		dst = LOAD_RM8(modrm);
		shift = FETCH(cpustate) & 0x1f;
		dst = i386_shift_rotate8(cpustate, modrm, dst, shift);
		STORE_RM8(modrm, dst);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		dst = READ8(cpustate,ea);
		shift = FETCH(cpustate) & 0x1f;
		dst = i386_shift_rotate8(cpustate, modrm, dst, shift);
		WRITE8(cpustate,ea, dst);
	}
}

static void I386OP(groupD0_8)(i386_state *cpustate)         // Opcode 0xd0
{
	UINT8 dst;
	UINT8 modrm = FETCH(cpustate);

	if( modrm >= 0xc0 ) {
		dst = LOAD_RM8(modrm);
		dst = i386_shift_rotate8(cpustate, modrm, dst, 1);
		STORE_RM8(modrm, dst);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		dst = READ8(cpustate,ea);
		dst = i386_shift_rotate8(cpustate, modrm, dst, 1);
		WRITE8(cpustate,ea, dst);
	}
}

static void I386OP(groupD2_8)(i386_state *cpustate)         // Opcode 0xd2
{
	UINT8 dst;
	UINT8 modrm = FETCH(cpustate);

	if( modrm >= 0xc0 ) {
		dst = LOAD_RM8(modrm);
		dst = i386_shift_rotate8(cpustate, modrm, dst, REG8(CL));
		STORE_RM8(modrm, dst);
	} else {
		UINT32 ea = GetEA(cpustate,modrm,1,1);
		dst = READ8(cpustate,ea);
		dst = i386_shift_rotate8(cpustate, modrm, dst, REG8(CL));
		WRITE8(cpustate,ea, dst);
	}
}

static void I386OP(groupF6_8)(i386_state *cpustate)         // Opcode 0xf6
{
	UINT8 modrm = FETCH(cpustate);

	switch( (modrm >> 3) & 0x7 )
	{
		case 0:         /* TEST Rm8, i8 */
			if( modrm >= 0xc0 ) {
				UINT8 dst = LOAD_RM8(modrm);
				UINT8 src = FETCH(cpustate);
				dst &= src;
				cpustate->CF = cpustate->OF = cpustate->AF = 0;
				SetSZPF8(dst);
				CYCLES(cpustate,CYCLES_TEST_IMM_REG);
			} else {
				UINT32 ea = GetEA(cpustate,modrm,0,1);
				UINT8 dst = READ8(cpustate,ea);
				UINT8 src = FETCH(cpustate);
				dst &= src;
				cpustate->CF = cpustate->OF = cpustate->AF = 0;
				SetSZPF8(dst);
				CYCLES(cpustate,CYCLES_TEST_IMM_MEM);
			}
			break;
		case 2:         /* NOT Rm8 */
			if( modrm >= 0xc0 ) {
				UINT8 dst = LOAD_RM8(modrm);
				dst = ~dst;
				STORE_RM8(modrm, dst);
				CYCLES(cpustate,CYCLES_NOT_REG);
			} else {
				UINT32 ea = GetEA(cpustate,modrm,1,1);
				UINT8 dst = READ8(cpustate,ea);
				dst = ~dst;
				WRITE8(cpustate,ea, dst);
				CYCLES(cpustate,CYCLES_NOT_MEM);
			}
			break;
		case 3:         /* NEG Rm8 */
			if( modrm >= 0xc0 ) {
				UINT8 dst = LOAD_RM8(modrm);
				dst = SUB8(cpustate, 0, dst );
				STORE_RM8(modrm, dst);
				CYCLES(cpustate,CYCLES_NEG_REG);
			} else {
				UINT32 ea = GetEA(cpustate,modrm,1,1);
				UINT8 dst = READ8(cpustate,ea);
				dst = SUB8(cpustate, 0, dst );
				WRITE8(cpustate,ea, dst);
				CYCLES(cpustate,CYCLES_NEG_MEM);
			}
			break;
		case 4:         /* MUL AL, Rm8 */
			{
				UINT16 result;
				UINT8 src, dst;
				if( modrm >= 0xc0 ) {
					src = LOAD_RM8(modrm);
					CYCLES(cpustate,CYCLES_MUL8_ACC_REG);       /* TODO: Correct multiply timing */
				} else {
					UINT32 ea = GetEA(cpustate,modrm,0,1);
					src = READ8(cpustate,ea);
					CYCLES(cpustate,CYCLES_MUL8_ACC_MEM);       /* TODO: Correct multiply timing */
				}

				dst = REG8(AL);
				result = (UINT16)src * (UINT16)dst;
				REG16(AX) = (UINT16)result;

				cpustate->CF = cpustate->OF = (REG16(AX) > 0xff);
			}
			break;
		case 5:         /* IMUL AL, Rm8 */
			{
				INT16 result;
				INT16 src, dst;
				if( modrm >= 0xc0 ) {
					src = (INT16)(INT8)LOAD_RM8(modrm);
					CYCLES(cpustate,CYCLES_IMUL8_ACC_REG);      /* TODO: Correct multiply timing */
				} else {
					UINT32 ea = GetEA(cpustate,modrm,0,1);
					src = (INT16)(INT8)READ8(cpustate,ea);
					CYCLES(cpustate,CYCLES_IMUL8_ACC_MEM);      /* TODO: Correct multiply timing */
				}

				dst = (INT16)(INT8)REG8(AL);
				result = src * dst;

				REG16(AX) = (UINT16)result;

				cpustate->CF = cpustate->OF = !(result == (INT16)(INT8)result);
			}
			break;
		case 6:         /* DIV AL, Rm8 */
			{
				UINT16 quotient, remainder, result;
				UINT8 src;
				if( modrm >= 0xc0 ) {
					src = LOAD_RM8(modrm);
					CYCLES(cpustate,CYCLES_DIV8_ACC_REG);
				} else {
					UINT32 ea = GetEA(cpustate,modrm,0,1);
					src = READ8(cpustate,ea);
					CYCLES(cpustate,CYCLES_DIV8_ACC_MEM);
				}

				quotient = (UINT16)REG16(AX);
				if( src ) {
					remainder = quotient % (UINT16)src;
					result = quotient / (UINT16)src;
					if( result > 0xff ) {
						/* TODO: Divide error */
					} else {
						REG8(AH) = (UINT8)remainder & 0xff;
						REG8(AL) = (UINT8)result & 0xff;

						// this flag is actually undefined, enable on non-cyrix
						if (cpustate->cpuid_id0 != 0x69727943)
							cpustate->CF = 1;
					}
				} else {
					//i386_trap(cpustate, 0, 0, 0);
					FAULT(FAULT_DE, 0);
				}
			}
			break;
		case 7:         /* IDIV AL, Rm8 */
			{
				INT16 quotient, remainder, result;
				UINT8 src;
				if( modrm >= 0xc0 ) {
					src = LOAD_RM8(modrm);
					CYCLES(cpustate,CYCLES_IDIV8_ACC_REG);
				} else {
					UINT32 ea = GetEA(cpustate,modrm,0,1);
					src = READ8(cpustate,ea);
					CYCLES(cpustate,CYCLES_IDIV8_ACC_MEM);
				}

				quotient = (INT16)REG16(AX);
				if( src ) {
					remainder = quotient % (INT16)(INT8)src;
					result = quotient / (INT16)(INT8)src;
					if( result > 0xff ) {
						/* TODO: Divide error */
					} else {
						REG8(AH) = (UINT8)remainder & 0xff;
						REG8(AL) = (UINT8)result & 0xff;

						// this flag is actually undefined, enable on non-cyrix
						if (cpustate->cpuid_id0 != 0x69727943)
							cpustate->CF = 1;
					}
				} else {
					FAULT(FAULT_DE, 0);
					//i386_trap(cpustate, 0, 0, 0);
				}
			}
			break;
	}
}

static void I386OP(groupFE_8)(i386_state *cpustate)         // Opcode 0xfe
{
	UINT8 modrm = FETCH(cpustate);

	switch( (modrm >> 3) & 0x7 )
	{
		case 0:         /* INC Rm8 */
			if( modrm >= 0xc0 ) {
				UINT8 dst = LOAD_RM8(modrm);
				dst = INC8(cpustate,dst);
				STORE_RM8(modrm, dst);
				CYCLES(cpustate,CYCLES_INC_REG);
			} else {
				UINT32 ea = GetEA(cpustate,modrm,1,1);
				UINT8 dst = READ8(cpustate,ea);
				dst = INC8(cpustate,dst);
				WRITE8(cpustate,ea, dst);
				CYCLES(cpustate,CYCLES_INC_MEM);
			}
			break;
		case 1:         /* DEC Rm8 */
			if( modrm >= 0xc0 ) {
				UINT8 dst = LOAD_RM8(modrm);
				dst = DEC8(cpustate,dst);
				STORE_RM8(modrm, dst);
				CYCLES(cpustate,CYCLES_DEC_REG);
			} else {
				UINT32 ea = GetEA(cpustate,modrm,1,1);
				UINT8 dst = READ8(cpustate,ea);
				dst = DEC8(cpustate,dst);
				WRITE8(cpustate,ea, dst);
				CYCLES(cpustate,CYCLES_DEC_MEM);
			}
			break;
		case 6:         /* PUSH Rm8*/
			{
				UINT8 value;
				if( modrm >= 0xc0 ) {
					value = LOAD_RM8(modrm);
				} else {
					UINT32 ea = GetEA(cpustate,modrm,0,1);
					value = READ8(cpustate,ea);
				}
				if( cpustate->operand_size ) {
					PUSH32(cpustate,value);
				} else {
					PUSH16(cpustate,value);
				}
				CYCLES(cpustate,CYCLES_PUSH_RM);
			}
			break;
		default:
			report_invalid_modrm(cpustate, "groupFE_8", modrm);
			break;
	}
}



static void I386OP(segment_CS)(i386_state *cpustate)        // Opcode 0x2e
{
	cpustate->segment_prefix = 1;
	cpustate->segment_override = CS;

	I386OP(decode_opcode)(cpustate);
}

static void I386OP(segment_DS)(i386_state *cpustate)        // Opcode 0x3e
{
	cpustate->segment_prefix = 1;
	cpustate->segment_override = DS;
	CYCLES(cpustate,0); // TODO: Specify cycle count
	I386OP(decode_opcode)(cpustate);
}

static void I386OP(segment_ES)(i386_state *cpustate)        // Opcode 0x26
{
	cpustate->segment_prefix = 1;
	cpustate->segment_override = ES;
	CYCLES(cpustate,0); // TODO: Specify cycle count
	I386OP(decode_opcode)(cpustate);
}

static void I386OP(segment_FS)(i386_state *cpustate)        // Opcode 0x64
{
	cpustate->segment_prefix = 1;
	cpustate->segment_override = FS;
	CYCLES(cpustate,1); // TODO: Specify cycle count
	I386OP(decode_opcode)(cpustate);
}

static void I386OP(segment_GS)(i386_state *cpustate)        // Opcode 0x65
{
	cpustate->segment_prefix = 1;
	cpustate->segment_override = GS;
	CYCLES(cpustate,1); // TODO: Specify cycle count
	I386OP(decode_opcode)(cpustate);
}

static void I386OP(segment_SS)(i386_state *cpustate)        // Opcode 0x36
{
	cpustate->segment_prefix = 1;
	cpustate->segment_override = SS;
	CYCLES(cpustate,0); // TODO: Specify cycle count
	I386OP(decode_opcode)(cpustate);
}

static void I386OP(operand_size)(i386_state *cpustate)      // Opcode prefix 0x66
{
	if(cpustate->operand_prefix == 0)
	{
		cpustate->operand_size ^= 1;
		cpustate->xmm_operand_size ^= 1;
		cpustate->operand_prefix = 1;
	}
	cpustate->opcode = FETCH(cpustate);
	if (cpustate->opcode == 0x0f)
		I386OP(decode_three_byte66)(cpustate);
	else
	{
		if( cpustate->operand_size )
			cpustate->opcode_table1_32[cpustate->opcode](cpustate);
		else
			cpustate->opcode_table1_16[cpustate->opcode](cpustate);
	}
}

static void I386OP(address_size)(i386_state *cpustate)      // Opcode 0x67
{
	if(cpustate->address_prefix == 0)
	{
		cpustate->address_size ^= 1;
		cpustate->address_prefix = 1;
	}
	I386OP(decode_opcode)(cpustate);
}

static void I386OP(nop)(i386_state *cpustate)               // Opcode 0x90
{
	CYCLES(cpustate,CYCLES_NOP);
}

static void I386OP(int3)(i386_state *cpustate)              // Opcode 0xcc
{
	CYCLES(cpustate,CYCLES_INT3);
	logerror("INT3 at %08X\n", cpustate->pc - 1);
	cpustate->ext = 0; // not an external interrupt
	i386_trap(cpustate,3, 1, 0);
	cpustate->ext = 1;
}

static void I386OP(int_16)(i386_state *cpustate)               // Opcode 0xcd
{
	int interrupt = FETCH(cpustate);
	CYCLES(cpustate,CYCLES_INT);
	//BIOS_INT(interrupt);
	BIOS_INT32(interrupt);
	
	cpustate->ext = 0; // not an external interrupt
	i386_trap(cpustate,interrupt, 1, 0);
	cpustate->ext = 1;
}

static void I386OP(int_32)(i386_state *cpustate)               // Opcode 0xcd
{
	int interrupt = FETCH(cpustate);
	CYCLES(cpustate,CYCLES_INT);
#if 1
	BIOS_INT32(interrupt);
#endif
	cpustate->ext = 0; // not an external interrupt
	i386_trap(cpustate,interrupt, 1, 0);
	cpustate->ext = 1;
}

static void I386OP(into)(i386_state *cpustate)              // Opcode 0xce
{
	if( cpustate->OF ) {
		cpustate->ext = 0;
		i386_trap(cpustate,4, 1, 0);
		cpustate->ext = 1;
		CYCLES(cpustate,CYCLES_INTO_OF1);
	}
	else
	{
		CYCLES(cpustate,CYCLES_INTO_OF0);
	}
}

static UINT32 i386_escape_ea;   // hack around GCC 4.6 error because we need the side effects of GetEA()
static void I386OP(escape)(i386_state *cpustate)            // Opcodes 0xd8 - 0xdf
{
	UINT8 modrm = FETCH(cpustate);
	if(modrm < 0xc0)
	{
		i386_escape_ea = GetEA(cpustate,modrm,0,1);
	}
	CYCLES(cpustate,3); // TODO: confirm this
	(void) LOAD_RM8(modrm);
}

static void I386OP(hlt)(i386_state *cpustate)               // Opcode 0xf4
{
	if(PROTECTED_MODE && cpustate->CPL != 0) {
		logerror("Call from no-supervisor privilege: I386OP(hlt)");
		FAULT(FAULT_GP,0);
		//cpustate->eip++;
		//cpustate->pc++;
		//return;
	}
	cpustate->halted = 1;
	CYCLES(cpustate,CYCLES_HLT);
	if (cpustate->cycles > 0)
		cpustate->cycles = 0;
}

static void I386OP(decimal_adjust)(i386_state *cpustate, int direction)
{
	UINT8 tmpAL = REG8(AL);
	UINT8 tmpCF = cpustate->CF;

	if (cpustate->AF || ((REG8(AL) & 0xf) > 9))
	{
		UINT16 t= (UINT16)REG8(AL) + (direction * 0x06);
		REG8(AL) = (UINT8)t&0xff;
		cpustate->AF = 1;
		if (t & 0x100)
			cpustate->CF = 1;
		if (direction > 0)
			tmpAL = REG8(AL);
	}

	if (tmpCF || (tmpAL > 0x99))
	{
		REG8(AL) += (direction * 0x60);
		cpustate->CF = 1;
	}

	SetSZPF8(REG8(AL));
}

static void I386OP(daa)(i386_state *cpustate)               // Opcode 0x27
{
	I386OP(decimal_adjust)(cpustate, +1);
	CYCLES(cpustate,CYCLES_DAA);
}

static void I386OP(das)(i386_state *cpustate)               // Opcode 0x2f
{
	I386OP(decimal_adjust)(cpustate, -1);
	CYCLES(cpustate,CYCLES_DAS);
}

static void I386OP(aaa)(i386_state *cpustate)               // Opcode 0x37
{
	if( ( (REG8(AL) & 0x0f) > 9) || (cpustate->AF != 0) ) {
		REG16(AX) = REG16(AX) + 6;
		REG8(AH) = REG8(AH) + 1;
		cpustate->AF = 1;
		cpustate->CF = 1;
	} else {
		cpustate->AF = 0;
		cpustate->CF = 0;
	}
	REG8(AL) = REG8(AL) & 0x0f;
	CYCLES(cpustate,CYCLES_AAA);
}

static void I386OP(aas)(i386_state *cpustate)               // Opcode 0x3f
{
	if (cpustate->AF || ((REG8(AL) & 0xf) > 9))
	{
		REG16(AX) -= 6;
		REG8(AH) -= 1;
		cpustate->AF = 1;
		cpustate->CF = 1;
	}
	else
	{
		cpustate->AF = 0;
		cpustate->CF = 0;
	}
	REG8(AL) &= 0x0f;
	CYCLES(cpustate,CYCLES_AAS);
}

static void I386OP(aad)(i386_state *cpustate)               // Opcode 0xd5
{
	UINT8 tempAL = REG8(AL);
	UINT8 tempAH = REG8(AH);
	UINT8 i = FETCH(cpustate);

	REG8(AL) = (tempAL + (tempAH * i)) & 0xff;
	REG8(AH) = 0;
	SetSZPF8( REG8(AL) );
	CYCLES(cpustate,CYCLES_AAD);
}

static void I386OP(aam)(i386_state *cpustate)               // Opcode 0xd4
{
	UINT8 tempAL = REG8(AL);
	UINT8 i = FETCH(cpustate);

	if(!i)
	{
		FAULT(FAULT_DE, 0);
		//i386_trap(cpustate, 0, 0, 0);
		return;
	}
	REG8(AH) = tempAL / i;
	REG8(AL) = tempAL % i;
	SetSZPF8( REG8(AL) );
	CYCLES(cpustate,CYCLES_AAM);
}

static void I386OP(clts)(i386_state *cpustate)              // Opcode 0x0f 0x06
{
	// Privileged instruction, CPL must be zero.  Can be used in real or v86 mode.
	if(PROTECTED_MODE && cpustate->CPL != 0) {
		logerror("Call from non-supervisor privilege: I386OP(clts)"); 
		FAULT(FAULT_GP,0)
		return;
	}
	cpustate->cr[0] &= ~0x08;   /* clear TS bit */
	CYCLES(cpustate,CYCLES_CLTS);
}

static void I386OP(wait)(i386_state *cpustate)              // Opcode 0x9B
{
	// TODO
}

static void I386OP(lock)(i386_state *cpustate)              // Opcode 0xf0
{
	// lock doesn't depend on iopl on 386
	cpustate->lock = true;
	CYCLES(cpustate,CYCLES_LOCK);       // TODO: Determine correct cycle count
	I386OP(decode_opcode)(cpustate);
}

static void I386OP(mov_r32_tr)(i386_state *cpustate)        // Opcode 0x0f 24
{
	FETCH(cpustate);
	CYCLES(cpustate,1);     // TODO: correct cycle count
}

static void I386OP(mov_tr_r32)(i386_state *cpustate)        // Opcode 0x0f 26
{
	FETCH(cpustate);
	CYCLES(cpustate,1);     // TODO: correct cycle count
}

static void I386OP(loadall)(i386_state *cpustate)       // Opcode 0x0f 0x07 (0x0f 0x05 on 80286), undocumented
{
	if(PROTECTED_MODE && (cpustate->CPL != 0)) {
		logerror("Call from non-supervisor privilege: I386OP(loadall)"); 
		FAULT(FAULT_GP,0)
		return;
	}
	logerror("LOADALL CS=%04X EIP=%08X PC=%08X\n", cpustate->sreg[CS].selector, cpustate->eip, cpustate->pc);
	UINT32 ea = i386_translate(cpustate, ES, REG32(EDI), 0, 204);
	cpustate->cr[0] = READ32(cpustate, ea) & 0xfffeffff; // wp not supported on 386
	set_flags(cpustate, READ32(cpustate, ea + 0x04));
	cpustate->eip = READ32(cpustate, ea + 0x08);
	REG32(EDI) = READ32(cpustate, ea + 0x0c);
	REG32(ESI) = READ32(cpustate, ea + 0x10);
	REG32(EBP) = READ32(cpustate, ea + 0x14);
	REG32(ESP) = READ32(cpustate, ea + 0x18);
	REG32(EBX) = READ32(cpustate, ea + 0x1c);
	REG32(EDX) = READ32(cpustate, ea + 0x20);
	REG32(ECX) = READ32(cpustate, ea + 0x24);
	REG32(EAX) = READ32(cpustate, ea + 0x28);
	cpustate->dr[6] = READ32(cpustate, ea + 0x2c);
	cpustate->dr[7] = READ32(cpustate, ea + 0x30);
	cpustate->task.segment = READ16(cpustate, ea + 0x34);
	cpustate->ldtr.segment = READ16(cpustate, ea + 0x38);
	cpustate->sreg[GS].selector = READ16(cpustate, ea + 0x3c);
	cpustate->sreg[FS].selector = READ16(cpustate, ea + 0x40);
	cpustate->sreg[DS].selector = READ16(cpustate, ea + 0x44);
	cpustate->sreg[SS].selector = READ16(cpustate, ea + 0x48);
	cpustate->sreg[CS].selector = READ16(cpustate, ea + 0x4c);
	cpustate->sreg[ES].selector = READ16(cpustate, ea + 0x50);
	cpustate->task.flags = READ32(cpustate, ea + 0x54) >> 8;
	cpustate->task.base = READ32(cpustate, ea + 0x58);
	cpustate->task.limit = READ32(cpustate, ea + 0x5c);
	cpustate->idtr.base = READ32(cpustate, ea + 0x64);
	cpustate->idtr.limit = READ32(cpustate, ea + 0x68);
	cpustate->gdtr.base = READ32(cpustate, ea + 0x70);
	cpustate->gdtr.limit = READ32(cpustate, ea + 0x74);
	cpustate->ldtr.flags = READ32(cpustate, ea + 0x78) >> 8;
	cpustate->ldtr.base = READ32(cpustate, ea + 0x7c);
	cpustate->ldtr.limit = READ32(cpustate, ea + 0x80);
	cpustate->sreg[GS].flags = READ32(cpustate, ea + 0x84) >> 8;
	cpustate->sreg[GS].base = READ32(cpustate, ea + 0x88);
	cpustate->sreg[GS].limit = READ32(cpustate, ea + 0x8c);
	cpustate->sreg[FS].flags = READ32(cpustate, ea + 0x90) >> 8;
	cpustate->sreg[FS].base = READ32(cpustate, ea + 0x94);
	cpustate->sreg[FS].limit = READ32(cpustate, ea + 0x98);
	cpustate->sreg[DS].flags = READ32(cpustate, ea + 0x9c) >> 8;
	cpustate->sreg[DS].base = READ32(cpustate, ea + 0xa0);
	cpustate->sreg[DS].limit = READ32(cpustate, ea + 0xa4);
	cpustate->sreg[SS].flags = READ32(cpustate, ea + 0xa8) >> 8;
	cpustate->sreg[SS].base = READ32(cpustate, ea + 0xac);
	cpustate->sreg[SS].limit = READ32(cpustate, ea + 0xb0);
	cpustate->sreg[CS].flags = READ32(cpustate, ea + 0xb4) >> 8;
	cpustate->sreg[CS].base = READ32(cpustate, ea + 0xb8);
	cpustate->sreg[CS].limit = READ32(cpustate, ea + 0xbc);
	cpustate->sreg[ES].flags = READ32(cpustate, ea + 0xc0) >> 8;
	cpustate->sreg[ES].base = READ32(cpustate, ea + 0xc4);
	cpustate->sreg[ES].limit = READ32(cpustate, ea + 0xc8);
	cpustate->CPL = (cpustate->sreg[SS].flags >> 5) & 3; // cpl == dpl of ss

	for(int i = 0; i <= GS; i++)
	{
		cpustate->sreg[i].valid = (cpustate->sreg[i].flags & 0x80) ? true : false;
		cpustate->sreg[i].d = (cpustate->sreg[i].flags & 0x4000) ? 1 : 0;
	}
	CHANGE_PC(cpustate, cpustate->eip);
}

static void I386OP(invalid)(i386_state *cpustate)
{
	report_invalid_opcode(cpustate);
	i386_trap(cpustate, 6, 0, 0);
}

static void I386OP(xlat)(i386_state *cpustate)          // Opcode 0xd7
{
	UINT32 ea;
	if( cpustate->segment_prefix ) {
		if(!cpustate->address_size)
		{
			ea = i386_translate(cpustate, cpustate->segment_override, REG16(BX) + REG8(AL), 0, 1 );
		}
		else
		{
			ea = i386_translate(cpustate, cpustate->segment_override, REG32(EBX) + REG8(AL), 0, 1 );
		}
	} else {
		if(!cpustate->address_size)
		{
			ea = i386_translate(cpustate, DS, REG16(BX) + REG8(AL), 0, 1 );
		}
		else
		{
			ea = i386_translate(cpustate, DS, REG32(EBX) + REG8(AL), 0, 1 );
		}
	}
	REG8(AL) = READ8(cpustate,ea);
	CYCLES(cpustate,CYCLES_XLAT);
}
