/* * COPYRIGHT: GPL - See COPYING in the top level directory * PROJECT: 386/486 CPU Emulation Library * FILE: opcodes.c * PURPOSE: Opcode handlers. * PROGRAMMERS: Aleksandar Andrejevic */ /* INCLUDES *******************************************************************/ // #define WIN32_NO_STATUS // #define _INC_WINDOWS #include #include #include "opcodes.h" #include "common.h" // #define NDEBUG #include /* PUBLIC VARIABLES ***********************************************************/ SOFT386_OPCODE_HANDLER_PROC Soft386OpcodeHandlers[SOFT386_NUM_OPCODE_HANDLERS] = { NULL, // TODO: OPCODE 0x00 NOT SUPPORTED NULL, // TODO: OPCODE 0x01 NOT SUPPORTED NULL, // TODO: OPCODE 0x02 NOT SUPPORTED NULL, // TODO: OPCODE 0x03 NOT SUPPORTED NULL, // TODO: OPCODE 0x04 NOT SUPPORTED NULL, // TODO: OPCODE 0x05 NOT SUPPORTED NULL, // TODO: OPCODE 0x06 NOT SUPPORTED NULL, // TODO: OPCODE 0x07 NOT SUPPORTED NULL, // TODO: OPCODE 0x08 NOT SUPPORTED NULL, // TODO: OPCODE 0x09 NOT SUPPORTED NULL, // TODO: OPCODE 0x0A NOT SUPPORTED NULL, // TODO: OPCODE 0x0B NOT SUPPORTED NULL, // TODO: OPCODE 0x0C NOT SUPPORTED NULL, // TODO: OPCODE 0x0D NOT SUPPORTED NULL, // TODO: OPCODE 0x0E NOT SUPPORTED NULL, // TODO: OPCODE 0x0F NOT SUPPORTED NULL, // TODO: OPCODE 0x10 NOT SUPPORTED NULL, // TODO: OPCODE 0x11 NOT SUPPORTED NULL, // TODO: OPCODE 0x12 NOT SUPPORTED NULL, // TODO: OPCODE 0x13 NOT SUPPORTED NULL, // TODO: OPCODE 0x14 NOT SUPPORTED NULL, // TODO: OPCODE 0x15 NOT SUPPORTED NULL, // TODO: OPCODE 0x16 NOT SUPPORTED NULL, // TODO: OPCODE 0x17 NOT SUPPORTED NULL, // TODO: OPCODE 0x18 NOT SUPPORTED NULL, // TODO: OPCODE 0x19 NOT SUPPORTED NULL, // TODO: OPCODE 0x1A NOT SUPPORTED NULL, // TODO: OPCODE 0x1B NOT SUPPORTED NULL, // TODO: OPCODE 0x1C NOT SUPPORTED NULL, // TODO: OPCODE 0x1D NOT SUPPORTED NULL, // TODO: OPCODE 0x1E NOT SUPPORTED NULL, // TODO: OPCODE 0x1F NOT SUPPORTED NULL, // TODO: OPCODE 0x20 NOT SUPPORTED NULL, // TODO: OPCODE 0x21 NOT SUPPORTED NULL, // TODO: OPCODE 0x22 NOT SUPPORTED NULL, // TODO: OPCODE 0x23 NOT SUPPORTED NULL, // TODO: OPCODE 0x24 NOT SUPPORTED NULL, // TODO: OPCODE 0x25 NOT SUPPORTED Soft386OpcodePrefix, NULL, // TODO: OPCODE 0x27 NOT SUPPORTED NULL, // TODO: OPCODE 0x28 NOT SUPPORTED NULL, // TODO: OPCODE 0x29 NOT SUPPORTED NULL, // TODO: OPCODE 0x2A NOT SUPPORTED NULL, // TODO: OPCODE 0x2B NOT SUPPORTED NULL, // TODO: OPCODE 0x2C NOT SUPPORTED NULL, // TODO: OPCODE 0x2D NOT SUPPORTED Soft386OpcodePrefix, NULL, // TODO: OPCODE 0x2F NOT SUPPORTED NULL, // TODO: OPCODE 0x30 NOT SUPPORTED NULL, // TODO: OPCODE 0x31 NOT SUPPORTED NULL, // TODO: OPCODE 0x32 NOT SUPPORTED NULL, // TODO: OPCODE 0x33 NOT SUPPORTED NULL, // TODO: OPCODE 0x34 NOT SUPPORTED NULL, // TODO: OPCODE 0x35 NOT SUPPORTED Soft386OpcodePrefix, NULL, // TODO: OPCODE 0x37 NOT SUPPORTED NULL, // TODO: OPCODE 0x38 NOT SUPPORTED NULL, // TODO: OPCODE 0x39 NOT SUPPORTED NULL, // TODO: OPCODE 0x3A NOT SUPPORTED NULL, // TODO: OPCODE 0x3B NOT SUPPORTED NULL, // TODO: OPCODE 0x3C NOT SUPPORTED NULL, // TODO: OPCODE 0x3D NOT SUPPORTED Soft386OpcodePrefix, NULL, // TODO: OPCODE 0x3F NOT SUPPORTED Soft386OpcodeIncrement, Soft386OpcodeIncrement, Soft386OpcodeIncrement, Soft386OpcodeIncrement, Soft386OpcodeIncrement, Soft386OpcodeIncrement, Soft386OpcodeIncrement, Soft386OpcodeIncrement, Soft386OpcodeDecrement, Soft386OpcodeDecrement, Soft386OpcodeDecrement, Soft386OpcodeDecrement, Soft386OpcodeDecrement, Soft386OpcodeDecrement, Soft386OpcodeDecrement, Soft386OpcodeDecrement, Soft386OpcodePushReg, Soft386OpcodePushReg, Soft386OpcodePushReg, Soft386OpcodePushReg, Soft386OpcodePushReg, Soft386OpcodePushReg, Soft386OpcodePushReg, Soft386OpcodePushReg, Soft386OpcodePopReg, Soft386OpcodePopReg, Soft386OpcodePopReg, Soft386OpcodePopReg, Soft386OpcodePopReg, Soft386OpcodePopReg, Soft386OpcodePopReg, Soft386OpcodePopReg, NULL, // TODO: OPCODE 0x60 NOT SUPPORTED NULL, // TODO: OPCODE 0x61 NOT SUPPORTED NULL, // TODO: OPCODE 0x62 NOT SUPPORTED NULL, // TODO: OPCODE 0x63 NOT SUPPORTED Soft386OpcodePrefix, Soft386OpcodePrefix, Soft386OpcodePrefix, Soft386OpcodePrefix, NULL, // TODO: OPCODE 0x68 NOT SUPPORTED NULL, // TODO: OPCODE 0x69 NOT SUPPORTED NULL, // TODO: OPCODE 0x6A NOT SUPPORTED NULL, // TODO: OPCODE 0x6B NOT SUPPORTED NULL, // TODO: OPCODE 0x6C NOT SUPPORTED NULL, // TODO: OPCODE 0x6D NOT SUPPORTED NULL, // TODO: OPCODE 0x6E NOT SUPPORTED NULL, // TODO: OPCODE 0x6F NOT SUPPORTED Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, Soft386OpcodeShortConditionalJmp, NULL, // TODO: OPCODE 0x80 NOT SUPPORTED NULL, // TODO: OPCODE 0x81 NOT SUPPORTED NULL, // TODO: OPCODE 0x82 NOT SUPPORTED NULL, // TODO: OPCODE 0x83 NOT SUPPORTED NULL, // TODO: OPCODE 0x84 NOT SUPPORTED NULL, // TODO: OPCODE 0x85 NOT SUPPORTED NULL, // TODO: OPCODE 0x86 NOT SUPPORTED NULL, // TODO: OPCODE 0x87 NOT SUPPORTED NULL, // TODO: OPCODE 0x88 NOT SUPPORTED NULL, // TODO: OPCODE 0x89 NOT SUPPORTED NULL, // TODO: OPCODE 0x8A NOT SUPPORTED NULL, // TODO: OPCODE 0x8B NOT SUPPORTED NULL, // TODO: OPCODE 0x8C NOT SUPPORTED NULL, // TODO: OPCODE 0x8D NOT SUPPORTED NULL, // TODO: OPCODE 0x8E NOT SUPPORTED NULL, // TODO: OPCODE 0x8F NOT SUPPORTED Soft386OpcodeNop, Soft386OpcodeExchangeEax, Soft386OpcodeExchangeEax, Soft386OpcodeExchangeEax, Soft386OpcodeExchangeEax, Soft386OpcodeExchangeEax, Soft386OpcodeExchangeEax, Soft386OpcodeExchangeEax, NULL, // TODO: OPCODE 0x98 NOT SUPPORTED NULL, // TODO: OPCODE 0x99 NOT SUPPORTED NULL, // TODO: OPCODE 0x9A NOT SUPPORTED NULL, // TODO: OPCODE 0x9B NOT SUPPORTED NULL, // TODO: OPCODE 0x9C NOT SUPPORTED NULL, // TODO: OPCODE 0x9D NOT SUPPORTED NULL, // TODO: OPCODE 0x9E NOT SUPPORTED NULL, // TODO: OPCODE 0x9F NOT SUPPORTED NULL, // TODO: OPCODE 0xA0 NOT SUPPORTED NULL, // TODO: OPCODE 0xA1 NOT SUPPORTED NULL, // TODO: OPCODE 0xA2 NOT SUPPORTED NULL, // TODO: OPCODE 0xA3 NOT SUPPORTED NULL, // TODO: OPCODE 0xA4 NOT SUPPORTED NULL, // TODO: OPCODE 0xA5 NOT SUPPORTED NULL, // TODO: OPCODE 0xA6 NOT SUPPORTED NULL, // TODO: OPCODE 0xA7 NOT SUPPORTED NULL, // TODO: OPCODE 0xA8 NOT SUPPORTED NULL, // TODO: OPCODE 0xA9 NOT SUPPORTED NULL, // TODO: OPCODE 0xAA NOT SUPPORTED NULL, // TODO: OPCODE 0xAB NOT SUPPORTED NULL, // TODO: OPCODE 0xAC NOT SUPPORTED NULL, // TODO: OPCODE 0xAD NOT SUPPORTED NULL, // TODO: OPCODE 0xAE NOT SUPPORTED NULL, // TODO: OPCODE 0xAF NOT SUPPORTED NULL, // TODO: OPCODE 0xB0 NOT SUPPORTED NULL, // TODO: OPCODE 0xB1 NOT SUPPORTED NULL, // TODO: OPCODE 0xB2 NOT SUPPORTED NULL, // TODO: OPCODE 0xB3 NOT SUPPORTED NULL, // TODO: OPCODE 0xB4 NOT SUPPORTED NULL, // TODO: OPCODE 0xB5 NOT SUPPORTED NULL, // TODO: OPCODE 0xB6 NOT SUPPORTED NULL, // TODO: OPCODE 0xB7 NOT SUPPORTED NULL, // TODO: OPCODE 0xB8 NOT SUPPORTED NULL, // TODO: OPCODE 0xB9 NOT SUPPORTED NULL, // TODO: OPCODE 0xBA NOT SUPPORTED NULL, // TODO: OPCODE 0xBB NOT SUPPORTED NULL, // TODO: OPCODE 0xBC NOT SUPPORTED NULL, // TODO: OPCODE 0xBD NOT SUPPORTED NULL, // TODO: OPCODE 0xBE NOT SUPPORTED NULL, // TODO: OPCODE 0xBF NOT SUPPORTED NULL, // TODO: OPCODE 0xC0 NOT SUPPORTED NULL, // TODO: OPCODE 0xC1 NOT SUPPORTED NULL, // TODO: OPCODE 0xC2 NOT SUPPORTED NULL, // TODO: OPCODE 0xC3 NOT SUPPORTED NULL, // TODO: OPCODE 0xC4 NOT SUPPORTED NULL, // TODO: OPCODE 0xC5 NOT SUPPORTED NULL, // TODO: OPCODE 0xC6 NOT SUPPORTED NULL, // TODO: OPCODE 0xC7 NOT SUPPORTED NULL, // TODO: OPCODE 0xC8 NOT SUPPORTED NULL, // TODO: OPCODE 0xC9 NOT SUPPORTED NULL, // TODO: OPCODE 0xCA NOT SUPPORTED NULL, // TODO: OPCODE 0xCB NOT SUPPORTED NULL, // TODO: OPCODE 0xCC NOT SUPPORTED NULL, // TODO: OPCODE 0xCD NOT SUPPORTED NULL, // TODO: OPCODE 0xCE NOT SUPPORTED NULL, // TODO: OPCODE 0xCF NOT SUPPORTED NULL, // TODO: OPCODE 0xD0 NOT SUPPORTED NULL, // TODO: OPCODE 0xD1 NOT SUPPORTED NULL, // TODO: OPCODE 0xD2 NOT SUPPORTED NULL, // TODO: OPCODE 0xD3 NOT SUPPORTED NULL, // TODO: OPCODE 0xD4 NOT SUPPORTED NULL, // TODO: OPCODE 0xD5 NOT SUPPORTED NULL, // TODO: OPCODE 0xD6 NOT SUPPORTED NULL, // TODO: OPCODE 0xD7 NOT SUPPORTED NULL, // TODO: OPCODE 0xD8 NOT SUPPORTED NULL, // TODO: OPCODE 0xD9 NOT SUPPORTED NULL, // TODO: OPCODE 0xDA NOT SUPPORTED NULL, // TODO: OPCODE 0xDB NOT SUPPORTED NULL, // TODO: OPCODE 0xDC NOT SUPPORTED NULL, // TODO: OPCODE 0xDD NOT SUPPORTED NULL, // TODO: OPCODE 0xDE NOT SUPPORTED NULL, // TODO: OPCODE 0xDF NOT SUPPORTED NULL, // TODO: OPCODE 0xE0 NOT SUPPORTED NULL, // TODO: OPCODE 0xE1 NOT SUPPORTED NULL, // TODO: OPCODE 0xE2 NOT SUPPORTED NULL, // TODO: OPCODE 0xE3 NOT SUPPORTED Soft386OpcodeInByte, Soft386OpcodeIn, Soft386OpcodeOutByte, Soft386OpcodeOut, NULL, // TODO: OPCODE 0xE8 NOT SUPPORTED NULL, // TODO: OPCODE 0xE9 NOT SUPPORTED NULL, // TODO: OPCODE 0xEA NOT SUPPORTED Soft386OpcodeShortJump, Soft386OpcodeInByte, Soft386OpcodeIn, Soft386OpcodeOutByte, Soft386OpcodeOut, Soft386OpcodePrefix, NULL, // Invalid Soft386OpcodePrefix, Soft386OpcodePrefix, Soft386OpcodeHalt, Soft386OpcodeComplCarry, NULL, // TODO: OPCODE 0xF6 NOT SUPPORTED NULL, // TODO: OPCODE 0xF7 NOT SUPPORTED Soft386OpcodeClearCarry, Soft386OpcodeSetCarry, Soft386OpcodeClearInt, Soft386OpcodeSetInt, Soft386OpcodeClearDir, Soft386OpcodeSetDir, NULL, // TODO: OPCODE 0xFE NOT SUPPORTED NULL, // TODO: OPCODE 0xFF NOT SUPPORTED }; BOOLEAN FASTCALL Soft386OpcodePrefix(PSOFT386_STATE State, UCHAR Opcode) { BOOLEAN Valid = FALSE; switch (Opcode) { /* ES: */ case 0x26: { if (!(State->PrefixFlags & SOFT386_PREFIX_SEG)) { State->PrefixFlags |= SOFT386_PREFIX_SEG; State->SegmentOverride = SOFT386_REG_ES; Valid = TRUE; } break; } /* CS: */ case 0x2E: { if (!(State->PrefixFlags & SOFT386_PREFIX_SEG)) { State->PrefixFlags |= SOFT386_PREFIX_SEG; State->SegmentOverride = SOFT386_REG_CS; Valid = TRUE; } break; } /* SS: */ case 0x36: { if (!(State->PrefixFlags & SOFT386_PREFIX_SEG)) { State->PrefixFlags |= SOFT386_PREFIX_SEG; State->SegmentOverride = SOFT386_REG_SS; Valid = TRUE; } break; } /* DS: */ case 0x3E: { if (!(State->PrefixFlags & SOFT386_PREFIX_SEG)) { State->PrefixFlags |= SOFT386_PREFIX_SEG; State->SegmentOverride = SOFT386_REG_DS; Valid = TRUE; } break; } /* FS: */ case 0x64: { if (!(State->PrefixFlags & SOFT386_PREFIX_SEG)) { State->PrefixFlags |= SOFT386_PREFIX_SEG; State->SegmentOverride = SOFT386_REG_FS; Valid = TRUE; } break; } /* GS: */ case 0x65: { if (!(State->PrefixFlags & SOFT386_PREFIX_SEG)) { State->PrefixFlags |= SOFT386_PREFIX_SEG; State->SegmentOverride = SOFT386_REG_GS; Valid = TRUE; } break; } /* OPSIZE */ case 0x66: { if (!(State->PrefixFlags & SOFT386_PREFIX_OPSIZE)) { State->PrefixFlags |= SOFT386_PREFIX_OPSIZE; Valid = TRUE; } break; } /* ADSIZE */ case 0x67: { if (!(State->PrefixFlags & SOFT386_PREFIX_ADSIZE)) { State->PrefixFlags |= SOFT386_PREFIX_ADSIZE; Valid = TRUE; } break; } /* LOCK */ case 0xF0: { if (!(State->PrefixFlags & SOFT386_PREFIX_LOCK)) { State->PrefixFlags |= SOFT386_PREFIX_LOCK; Valid = TRUE; } break; } /* REPNZ */ case 0xF2: { /* Mutually exclusive with REP */ if (!(State->PrefixFlags & (SOFT386_PREFIX_REPNZ | SOFT386_PREFIX_REP))) { State->PrefixFlags |= SOFT386_PREFIX_REPNZ; Valid = TRUE; } break; } /* REP / REPZ */ case 0xF3: { /* Mutually exclusive with REPNZ */ if (!(State->PrefixFlags & (SOFT386_PREFIX_REPNZ | SOFT386_PREFIX_REP))) { State->PrefixFlags |= SOFT386_PREFIX_REP; Valid = TRUE; } break; } } if (!Valid) { /* Clear all prefixes */ State->PrefixFlags = 0; /* Throw an exception */ Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } return TRUE; } BOOLEAN FASTCALL Soft386OpcodeIncrement(PSOFT386_STATE State, UCHAR Opcode) { ULONG Value; BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size; if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE) { /* The OPSIZE prefix toggles the size */ Size = !Size; } else if (State->PrefixFlags != 0) { /* Invalid prefix */ Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } /* Make sure this is the right instruction */ ASSERT((Opcode & 0xF8) == 0x40); if (Size) { Value = ++State->GeneralRegs[Opcode & 0x07].Long; State->Flags.Of = (Value == SIGN_FLAG_LONG) ? TRUE : FALSE; State->Flags.Sf = (Value & SIGN_FLAG_LONG) ? TRUE : FALSE; } else { Value = ++State->GeneralRegs[Opcode & 0x07].LowWord; State->Flags.Of = (Value == SIGN_FLAG_WORD) ? TRUE : FALSE; State->Flags.Sf = (Value & SIGN_FLAG_WORD) ? TRUE : FALSE; } State->Flags.Zf = (Value == 0) ? TRUE : FALSE; State->Flags.Af = ((Value & 0x0F) == 0) ? TRUE : FALSE; State->Flags.Pf = Soft386CalculateParity(LOBYTE(Value)); /* Return success */ return TRUE; } BOOLEAN FASTCALL Soft386OpcodeDecrement(PSOFT386_STATE State, UCHAR Opcode) { ULONG Value; BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size; if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE) { /* The OPSIZE prefix toggles the size */ Size = !Size; } else if (State->PrefixFlags != 0) { /* Invalid prefix */ Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } /* Make sure this is the right instruction */ ASSERT((Opcode & 0xF8) == 0x48); if (Size) { Value = --State->GeneralRegs[Opcode & 0x07].Long; State->Flags.Of = (Value == (SIGN_FLAG_LONG - 1)) ? TRUE : FALSE; State->Flags.Sf = (Value & SIGN_FLAG_LONG) ? TRUE : FALSE; } else { Value = --State->GeneralRegs[Opcode & 0x07].LowWord; State->Flags.Of = (Value == (SIGN_FLAG_WORD - 1)) ? TRUE : FALSE; State->Flags.Sf = (Value & SIGN_FLAG_WORD) ? TRUE : FALSE; } State->Flags.Zf = (Value == 0) ? TRUE : FALSE; State->Flags.Af = ((Value & 0x0F) == 0x0F) ? TRUE : FALSE; State->Flags.Pf = Soft386CalculateParity(LOBYTE(Value)); /* Return success */ return TRUE; } BOOLEAN FASTCALL Soft386OpcodePushReg(PSOFT386_STATE State, UCHAR Opcode) { if ((State->PrefixFlags != SOFT386_PREFIX_OPSIZE) && (State->PrefixFlags != 0)) { /* Invalid prefix */ Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } /* Make sure this is the right instruction */ ASSERT((Opcode & 0xF8) == 0x50); /* Call the internal function */ return Soft386StackPush(State, State->GeneralRegs[Opcode & 0x07].Long); } BOOLEAN FASTCALL Soft386OpcodePopReg(PSOFT386_STATE State, UCHAR Opcode) { ULONG Value; BOOLEAN Size = State->SegmentRegs[SOFT386_REG_SS].Size; if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE) { /* The OPSIZE prefix toggles the size */ Size = !Size; } else if (State->PrefixFlags != 0) { /* Invalid prefix */ Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } /* Make sure this is the right instruction */ ASSERT((Opcode & 0xF8) == 0x58); /* Call the internal function */ if (!Soft386StackPop(State, &Value)) return FALSE; /* Store the value */ if (Size) State->GeneralRegs[Opcode & 0x07].Long = Value; else State->GeneralRegs[Opcode & 0x07].LowWord = Value; /* Return success */ return TRUE; } BOOLEAN FASTCALL Soft386OpcodeNop(PSOFT386_STATE State, UCHAR Opcode) { if (State->PrefixFlags & ~(SOFT386_PREFIX_OPSIZE | SOFT386_PREFIX_REP)) { /* Allowed prefixes are REP and OPSIZE */ Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } if (State->PrefixFlags & SOFT386_PREFIX_REP) { /* Idle cycle */ State->IdleCallback(State); } return TRUE; } BOOLEAN FASTCALL Soft386OpcodeExchangeEax(PSOFT386_STATE State, UCHAR Opcode) { INT Reg = Opcode & 0x07; BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size; if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE) { /* The OPSIZE prefix toggles the size */ Size = !Size; } else if (State->PrefixFlags != 0) { /* Invalid prefix */ Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } /* Make sure this is the right instruction */ ASSERT((Opcode & 0xF8) == 0x90); /* Exchange the values */ if (Size) { ULONG Value; Value = State->GeneralRegs[Reg].Long; State->GeneralRegs[Reg].Long = State->GeneralRegs[SOFT386_REG_EAX].Long; State->GeneralRegs[SOFT386_REG_EAX].Long = Value; } else { USHORT Value; Value = State->GeneralRegs[Reg].LowWord; State->GeneralRegs[Reg].LowWord = State->GeneralRegs[SOFT386_REG_EAX].LowWord; State->GeneralRegs[SOFT386_REG_EAX].LowWord = Value; } return TRUE; } BOOLEAN FASTCALL Soft386OpcodeShortConditionalJmp(PSOFT386_STATE State, UCHAR Opcode) { BOOLEAN Jump = FALSE; CHAR Offset = 0; /* Make sure this is the right instruction */ ASSERT((Opcode & 0xF0) == 0x70); /* Fetch the offset */ if (!Soft386FetchByte(State, (PUCHAR)&Offset)) { /* An exception occurred */ return FALSE; } switch ((Opcode & 0x0F) >> 1) { /* JO / JNO */ case 0: { Jump = State->Flags.Of; break; } /* JC / JNC */ case 1: { Jump = State->Flags.Cf; break; } /* JZ / JNZ */ case 2: { Jump = State->Flags.Zf; break; } /* JBE / JNBE */ case 3: { Jump = State->Flags.Cf || State->Flags.Zf; break; } /* JS / JNS */ case 4: { Jump = State->Flags.Sf; break; } /* JP / JNP */ case 5: { Jump = State->Flags.Pf; break; } /* JL / JNL */ case 6: { Jump = State->Flags.Sf != State->Flags.Of; break; } /* JLE / JNLE */ case 7: { Jump = (State->Flags.Sf != State->Flags.Of) || State->Flags.Zf; break; } } if (Opcode & 1) { /* Invert the result */ Jump = !Jump; } if (Jump) { /* Move the instruction pointer */ State->InstPtr.Long += Offset; } /* Return success */ return TRUE; } BOOLEAN FASTCALL Soft386OpcodeClearCarry(PSOFT386_STATE State, UCHAR Opcode) { /* Make sure this is the right instruction */ ASSERT(Opcode == 0xF8); /* No prefixes allowed */ if (State->PrefixFlags) { Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } /* Clear CF and return success */ State->Flags.Cf = FALSE; return TRUE; } BOOLEAN FASTCALL Soft386OpcodeSetCarry(PSOFT386_STATE State, UCHAR Opcode) { /* Make sure this is the right instruction */ ASSERT(Opcode == 0xF9); /* No prefixes allowed */ if (State->PrefixFlags) { Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } /* Set CF and return success*/ State->Flags.Cf = TRUE; return TRUE; } BOOLEAN FASTCALL Soft386OpcodeComplCarry(PSOFT386_STATE State, UCHAR Opcode) { /* Make sure this is the right instruction */ ASSERT(Opcode == 0xF5); /* No prefixes allowed */ if (State->PrefixFlags) { Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } /* Toggle CF and return success */ State->Flags.Cf = !State->Flags.Cf; return TRUE; } BOOLEAN FASTCALL Soft386OpcodeClearInt(PSOFT386_STATE State, UCHAR Opcode) { /* Make sure this is the right instruction */ ASSERT(Opcode == 0xFA); /* No prefixes allowed */ if (State->PrefixFlags) { Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } /* Check for protected mode */ if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE) { /* Check IOPL */ if (State->Flags.Iopl >= State->SegmentRegs[SOFT386_REG_CS].Dpl) { /* Clear the interrupt flag */ State->Flags.If = FALSE; } else { /* General Protection Fault */ Soft386Exception(State, SOFT386_EXCEPTION_GP); return FALSE; } } else { /* Just clear the interrupt flag */ State->Flags.If = FALSE; } /* Return success */ return TRUE; } BOOLEAN FASTCALL Soft386OpcodeSetInt(PSOFT386_STATE State, UCHAR Opcode) { /* Make sure this is the right instruction */ ASSERT(Opcode == 0xFB); /* No prefixes allowed */ if (State->PrefixFlags) { Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } /* Check for protected mode */ if (State->ControlRegisters[SOFT386_REG_CR0] & SOFT386_CR0_PE) { /* Check IOPL */ if (State->Flags.Iopl >= State->SegmentRegs[SOFT386_REG_CS].Dpl) { /* Set the interrupt flag */ State->Flags.If = TRUE; } else { /* General Protection Fault */ Soft386Exception(State, SOFT386_EXCEPTION_GP); return FALSE; } } else { /* Just set the interrupt flag */ State->Flags.If = TRUE; } /* Return success */ return TRUE; } BOOLEAN FASTCALL Soft386OpcodeClearDir(PSOFT386_STATE State, UCHAR Opcode) { /* Make sure this is the right instruction */ ASSERT(Opcode == 0xFC); /* No prefixes allowed */ if (State->PrefixFlags) { Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } /* Clear DF and return success */ State->Flags.Df = FALSE; return TRUE; } BOOLEAN FASTCALL Soft386OpcodeSetDir(PSOFT386_STATE State, UCHAR Opcode) { /* Make sure this is the right instruction */ ASSERT(Opcode == 0xFD); /* No prefixes allowed */ if (State->PrefixFlags) { Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } /* Set DF and return success*/ State->Flags.Df = TRUE; return TRUE; } BOOLEAN FASTCALL Soft386OpcodeHalt(PSOFT386_STATE State, UCHAR Opcode) { /* Make sure this is the right instruction */ ASSERT(Opcode == 0xF4); /* No prefixes allowed */ if (State->PrefixFlags) { Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } /* Privileged instructions can only be executed under CPL = 0 */ if (State->SegmentRegs[SOFT386_REG_CS].Dpl != 0) { Soft386Exception(State, SOFT386_EXCEPTION_GP); return FALSE; } /* Halt */ while (!State->HardwareInt) State->IdleCallback(State); /* Return success */ return TRUE; } BOOLEAN FASTCALL Soft386OpcodeInByte(PSOFT386_STATE State, UCHAR Opcode) { UCHAR Data; ULONG Port; /* Make sure this is the right instruction */ ASSERT((Opcode & 0xF7) == 0xE4); if (Opcode == 0xE4) { /* Fetch the parameter */ if (!Soft386FetchByte(State, &Data)) { /* Exception occurred */ return FALSE; } /* Set the port number to the parameter */ Port = Data; } else { /* The port number is in DX */ Port = State->GeneralRegs[SOFT386_REG_EDX].LowWord; } /* Read a byte from the I/O port */ State->IoReadCallback(State, Port, &Data, sizeof(UCHAR)); /* Store the result in AL */ State->GeneralRegs[SOFT386_REG_EAX].LowByte = Data; return TRUE; } BOOLEAN FASTCALL Soft386OpcodeIn(PSOFT386_STATE State, UCHAR Opcode) { ULONG Port; BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size; /* Make sure this is the right instruction */ ASSERT((Opcode & 0xF7) == 0xE5); if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE) { /* The OPSIZE prefix toggles the size */ Size = !Size; } else if (State->PrefixFlags != 0) { /* Invalid prefix */ Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } if (Opcode == 0xE5) { UCHAR Data; /* Fetch the parameter */ if (!Soft386FetchByte(State, &Data)) { /* Exception occurred */ return FALSE; } /* Set the port number to the parameter */ Port = Data; } else { /* The port number is in DX */ Port = State->GeneralRegs[SOFT386_REG_EDX].LowWord; } if (Size) { ULONG Data; /* Read a dword from the I/O port */ State->IoReadCallback(State, Port, &Data, sizeof(ULONG)); /* Store the value in EAX */ State->GeneralRegs[SOFT386_REG_EAX].Long = Data; } else { USHORT Data; /* Read a word from the I/O port */ State->IoReadCallback(State, Port, &Data, sizeof(USHORT)); /* Store the value in AX */ State->GeneralRegs[SOFT386_REG_EAX].LowWord = Data; } return TRUE; } BOOLEAN FASTCALL Soft386OpcodeOutByte(PSOFT386_STATE State, UCHAR Opcode) { UCHAR Data; ULONG Port; /* Make sure this is the right instruction */ ASSERT((Opcode & 0xF7) == 0xE6); if (Opcode == 0xE6) { /* Fetch the parameter */ if (!Soft386FetchByte(State, &Data)) { /* Exception occurred */ return FALSE; } /* Set the port number to the parameter */ Port = Data; } else { /* The port number is in DX */ Port = State->GeneralRegs[SOFT386_REG_EDX].LowWord; } /* Read the value from AL */ Data = State->GeneralRegs[SOFT386_REG_EAX].LowByte; /* Write the byte to the I/O port */ State->IoWriteCallback(State, Port, &Data, sizeof(UCHAR)); return TRUE; } BOOLEAN FASTCALL Soft386OpcodeOut(PSOFT386_STATE State, UCHAR Opcode) { ULONG Port; BOOLEAN Size = State->SegmentRegs[SOFT386_REG_CS].Size; /* Make sure this is the right instruction */ ASSERT((Opcode & 0xF7) == 0xE7); if (State->PrefixFlags == SOFT386_PREFIX_OPSIZE) { /* The OPSIZE prefix toggles the size */ Size = !Size; } else if (State->PrefixFlags != 0) { /* Invalid prefix */ Soft386Exception(State, SOFT386_EXCEPTION_UD); return FALSE; } if (Opcode == 0xE7) { UCHAR Data; /* Fetch the parameter */ if (!Soft386FetchByte(State, &Data)) { /* Exception occurred */ return FALSE; } /* Set the port number to the parameter */ Port = Data; } else { /* The port number is in DX */ Port = State->GeneralRegs[SOFT386_REG_EDX].LowWord; } if (Size) { /* Get the value from EAX */ ULONG Data = State->GeneralRegs[SOFT386_REG_EAX].Long; /* Write a dword to the I/O port */ State->IoReadCallback(State, Port, &Data, sizeof(ULONG)); } else { /* Get the value from AX */ USHORT Data = State->GeneralRegs[SOFT386_REG_EAX].LowWord; /* Write a word to the I/O port */ State->IoWriteCallback(State, Port, &Data, sizeof(USHORT)); } return TRUE; } BOOLEAN FASTCALL Soft386OpcodeShortJump(PSOFT386_STATE State, UCHAR Opcode) { CHAR Offset = 0; /* Make sure this is the right instruction */ ASSERT(Opcode == 0xEB); /* Fetch the offset */ if (!Soft386FetchByte(State, (PUCHAR)&Offset)) { /* An exception occurred */ return FALSE; } /* Move the instruction pointer */ State->InstPtr.Long += Offset; return TRUE; }