NT4/private/ntos/nthals/haltyne/mips/x86lator.c
2020-09-30 17:12:29 +02:00

5882 lines
171 KiB
C

/*++
Copyright (c) 1994 DeskStation Technology, Inc.
Module Name:
xxbios.c
Abstract:
This module is an implementation of an 80286 emulator for performing
video adapter initialization and INT 10 video BIOS calls.
The main component of the emulator makes use of two lookup tables
for address and instruction decoding, and two variables of type
OPERAND that contain the decoded left and right operands. The
emulator looks at the first byte of the instruction. This 8 bit
value is used to lookup two functions in the DecodeOperandTable[].
The first function is called to decode the left operand, and the
second function is called to decode the right operand. The OPERAND
data type can contain a register, an immediate value, or a memory
location. The functions GetOperand() and PutOperand() allow the
values of the left and right operand to be retrieved and stored.
The DecodeInstructionTable[] is used to lookup the function to call
to execute the instruction once the left and right operands have been
decoded. The instruction type can be determined from the 8 bits in
the first byte of the instruction and bits 3-5 of the second byte
of the instruction. These 11 bits are used to lookup the appropriate
function in DecodeInstructionTable[]. This function is called. The
function associated with each instruction modifies the state of the
80286's internal registers, and the state of the memory system. The
address decode functions will have already moved the instruction
pointer to the beginning of the next instruction, so the main loop
of the emulator calls the address decode functions and the
instruction functions until the exit condition is met.
The emulator is invoked in two different ways. The first is when
the emulator is initialized. This initializes the state of all the
internal registers, and the state of the memory system. Then, a
check is made to see if a valid video BIOS is present in ISA memory.
If one is found, the emulator is invoked on the BIOS's initialization
code. The other way is to perform an INT 10 call. When an INT 10
call is made, it passes in a data structure containing the inital
values for AX,BX,CX,DX,SI,DI, and BP. The internal state of the
processor is initialized to these values, and the INT 10 vector
is looked up in memory. The CS and IP registers and initialized
to start executing the INT 10 call, and the exit condition is
initialized to stop the emulator when the INT 10 call returns.
When the INT 10 call returns, the values of the internal registers
are returned to the calling function. The calling function can
examine these registers to get at the INT 10's return value.
If the emulator encounters an error condition, the variable ErrorCode
will contain the reason for the error.
References:
Borland International, "Turbo Assembler Quick Reference Guide", 1990.
Choisser, John P., "The XT-AT Handbook", Annabooks, 1993.
Duncan, Ray, "IBM ROM BIOS", Microsoft Press, 1988.
Intel Corporation, "The 8086 Family Users's Manual", October 1979.
Intel Corporation, "Microprocessors Volume I", 1994.
"Macro Assembler by Microsoft" IBM Corporation, 1981.
Norton, Peter, "The New Peter Norton Programmer's Guide to the IBM
PC & PS/2", Microsoft Press, 1988.
Wilton, Richard, "Programmer's Guide to PC & PS/2 Video Systems",
Microsft Press, 1987.
Author:
Michael D. Kinney 19-Jun-1994
Environment:
Kernel mode only.
Revision History:
--*/
/***************************************************************************/
/* Include Files */
/***************************************************************************/
#include "nthal.h"
#include "hal.h"
#include "x86bios.h"
//#define X86DEBUG
//#define X86DEBUG1
/***************************************************************************/
/* Type Declarations */
/***************************************************************************/
typedef union REGISTER32
{
struct
{
UCHAR L;
UCHAR H;
};
USHORT X;
ULONG EX;
} REGISTER32;
typedef union REGISTERFLAG
{
struct
{
USHORT _cf:1;
USHORT _x1:1;
USHORT _pf:1;
USHORT _x3:1;
USHORT _af:1;
USHORT _x5:1;
USHORT _zf:1;
USHORT _sf:1;
USHORT _tf:1;
USHORT _if:1;
USHORT _df:1;
USHORT _of:1;
USHORT _x12:1;
USHORT _x13:1;
USHORT _x14:1;
USHORT _x15:1;
};
struct
{
UCHAR L;
UCHAR H;
};
USHORT X;
ULONG EX;
} REGISTERFLAG;
typedef enum { NullOperand,
Register8Operand, // 8 bit register operand
Register16Operand, // 16 bit register operand
Memory8Operand, // 8 bit memory reference (BYTE PTR)
Memory16Operand, // 16 bit memory reference (WORD PTR)
Immediate8Operand, // 8 bit immediate value
Immediate16Operand, // 16 bit immediate value
ShortLabelOperand, // 8 bit signed immediate value
Immediate32Operand // 32 bit immediate value forming a segment:offset memory reference.
} OPERANDTYPE;
typedef struct OPERAND
{
OPERANDTYPE OperandType;
UCHAR *Register8; // Pointer to 8 bit register variable
USHORT *Register16; // Pointer to 16 bit register variable
USHORT *MemorySegment; // Pointer to 16 bit segment register variable for memory address
REGISTER32 MemoryOffset; // 16 bit value for memory address
REGISTER32 Immediate8; // 8 bit value
REGISTER32 Immediate16; // 16 bit value
REGISTER32 ShortLabel; // 8 bit signed value
REGISTER32 Immediate32Segment; // 16 bit value for immediate address
REGISTER32 Immediate32Offset; // 16 bit value for immediate address
} OPERAND;
/***************************************************************************/
/* Register Access Macros */
/***************************************************************************/
//
// 16 Bit Instruction Pointer Register
//
#define IP (ip.X)
//
// 8 Bit General Purpose Registers
//
#define AL (a.L)
#define AH (a.H)
#define BL (b.L)
#define BH (b.H)
#define CL (c.L)
#define CH (c.H)
#define DL (d.L)
#define DH (d.H)
//
// 16 Bit General Purpose, Base and Index Registers
//
#define AX (a.X)
#define BX (b.X)
#define CX (c.X)
#define DX (d.X)
#define SP (sp.X)
#define BP (bp.X)
#define SI (si.X)
#define DI (di.X)
//
// 32 Bit General Purpose, Base and Index Registers
//
#define EAX (a.EX)
#define EBX (b.EX)
#define ECX (c.EX)
#define EDX (d.EX)
#define ESP (sp.EX)
#define EBP (bp.EX)
#define ESI (si.EX)
#define EDI (di.EX)
//
// 16 Bit Segment Registers
//
#define CS (cs.X)
#define DS (ds.X)
#define SS (ss.X)
#define ES (es.X)
//
// Flag Registers
//
#define CF (Flags._cf)
#define PF (Flags._pf)
#define AF (Flags._af)
#define ZF (Flags._zf)
#define SF (Flags._sf)
#define TF (Flags._tf)
#define IF (Flags._if)
#define DF (Flags._df)
#define OF (Flags._of)
//
// Debugging Macros
//
#ifdef X86DEBUG
static ULONG DebugOutFile;
static ULONG DebugInFile;
static ULONG DebugCount;
static UCHAR DebugGetChar;
static UCHAR PrintMessage[512];
static VOID CloseDebugPort()
{
Close(DebugOutFile);
}
static void SetBaudRate(ULONG Port,ULONG Rate)
{
ULONG Divisor;
Divisor = (24000000/13)/(Rate*16);
outp(Port+3,0x80);
outp(Port+0,Divisor & 0xff);
outp(Port+1,(Divisor>>8) & 0xff);
outp(Port+3,0x03);
}
static VOID OpenDebugPort()
{
ULONG Port = 0x3f8;
SetBaudRate(Port,9600);
outp(Port + 1,0x00);
outp(Port + 4,0x03);
}
static LONG SERRead(ULONG FileID,void *Buffer,ULONG N,ULONG *Count)
{
ULONG Port = 0x03f8;
for(*Count=0;*Count<N;(*Count)++)
{
while (!(inp(Port+5) & 0x0001));
*((CHAR *)(Buffer) + (*Count)) = inp(Port+0);
}
return(ESUCCESS);
}
static LONG SERWrite(ULONG FileID,void *Buffer,ULONG N,ULONG *Count)
{
ULONG Port = 0x3f8;
for(*Count=0;*Count<N;(*Count)++)
{
while (!(inp(Port+5) & 0x0020));
outp(Port,*((CHAR *)(Buffer)+(*Count)));
}
return(ESUCCESS);
}
#define DISPLAY(X) { OpenDebugPort(); SERWrite(DebugOutFile,X,strlen(X),&DebugCount); CloseDebugPort(); }
#define ERROR(X) DISPLAY(X)
#define PRINT1(X) sprintf(PrintMessage,X)
#define PRINT2(X,Y) sprintf(PrintMessage,X,Y)
#define PRINT3(X,Y,Z) sprintf(PrintMessage,X,Y,Z)
#define PRINT4(X,Y,Z,A) sprintf(PrintMessage,X,Y,Z,A)
#define STRCPY(X,Y) strcpy(X,Y)
#define STRCAT(X,Y) strcat(X,Y)
#define PAUSE { OpenDebugPort(); SERRead(DebugInFile,&DebugGetChar,1,&DebugCount); CloseDebugPort(); }
#define GETCHAR(X) { OpenDebugPort(); SERRead(DebugInFile,&X,1,&DebugCount); CloseDebugPort(); }
#define PUTCHAR(X) { OpenDebugPort(); SERWrite(DebugOutFile,&X,1,&DebugCount); CloseDebugPort(); }
#else
#define DISPLAY(X)
#define ERROR(X)
#define PRINT1(X)
#define PRINT2(X,Y)
#define PRINT3(X,Y,Z)
#define PRINT4(X,Y,Z,A)
#define STRCPY(X,Y)
#define STRCAT(X,Y)
#define PAUSE
#endif
#ifdef X86DEBUG1
#define ADDRESSTRACESIZE 80
static ULONG AddressTrace[ADDRESSTRACESIZE];
static ULONG AddressTracePosition;
#endif
/***************************************************************************/
/* Constants */
/***************************************************************************/
#define SUBOPERATION 0
#define ADDOPERATION 1
//
// Define table for computing parity.
//
static const UCHAR ParityTable[16] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
/***************************************************************************/
/* Global Variables */
/***************************************************************************/
static REGISTER32 ip; // x86 Processor Register IP.
static REGISTER32 a; // x86 Processor Register EAX,AX,AL,AH.
static REGISTER32 b; // x86 Processor Register EBX,BX,BL,BH.
static REGISTER32 c; // x86 Processor Register ECX,CX,CL,CH.
static REGISTER32 d; // x86 Processor Register EDX,DX,DL,DH.
static REGISTER32 sp; // x86 Processor Register ESP,SP.
static REGISTER32 bp; // x86 Processor Register EBP,BP.
static REGISTER32 si; // x86 Processor Register ESI,SI.
static REGISTER32 di; // x86 Processor Register ESI,DI.
static REGISTER32 es; // x86 Processor Register ES.
static REGISTER32 cs; // x86 Processor Register CS.
static REGISTER32 ss; // x86 Processor Register SS.
static REGISTER32 ds; // x86 Processor Register DS.
static REGISTERFLAG Flags; // x86 Processor Register CF,PF,AF,ZF,SF,TF,IF,DF,OF.
static USHORT msw; // 80286 Protected Mode Processor Register.
static USHORT gdtLimit; // 80286 Protected Mode Processor Register.
static ULONG gdtBase; // 80286 Protected Mode Processor Register.
static USHORT idtLimit; // 80286 Protected Mode Processor Register.
static ULONG idtBase; // 80286 Protected Mode Processor Register.
static ULONG CSCacheRegister=0xffffffff; // 80286 Protected Mode Processor Register.
static ULONG DSCacheRegister=0xffffffff; // 80286 Protected Mode Processor Register.
static ULONG ESCacheRegister=0xffffffff; // 80286 Protected Mode Processor Register.
static ULONG SSCacheRegister=0xffffffff; // 80286 Protected Mode Processor Register.
static ULONG BiosIsaIoBaseAddress; // Base virtual address of 64K ISA I/O space used by emulator.
static ULONG VDMBaseAddress; // Base virtual address of the 1MB area used by emulator.
static ULONG ISABaseAddress; // Base virtual address of ISA Memory.
static OPERAND LeftSource; // Storage area for left operand.
static OPERAND RightSource; // Storage area for right operand.
static OPERAND *LSRC = &LeftSource; // Pointer to left operand.
static OPERAND *RSRC = &RightSource; // Pointer to right operand.
static UCHAR OperationCodeByte; // 1st byte of instruction.
static UCHAR ExtendedOperationCodeByte; // 2nd byte of special 286 instructions.
static UCHAR InstructionSubIndex; // Value from 0-7 that is either 0 or the reg field from AddressModeByte.
static UCHAR AddressModeByte; // 2nd byte of instruction if instruction uses an address mode.
static UCHAR mod; // Address mode field.
static UCHAR reg; // Address mode field.
static UCHAR r_m; // Address mode field.
static ULONG SegmentOveridePrefix; // TRUE if a segment overide exists (CS:,DS:,ES:,SS:).
static USHORT *OverideSegmentRegister; // Pointer to 16 bit overide segment register.
static ULONG RepeatPrefix; // TRUE if a REP prefix exists.
static ULONG RepeatZeroFlag; // Flag for REPNZ and REPZ instructions.
static ULONG LockPrefix; // TRUE if a LOCK prefix exists.
static REGISTER32 CurrentIP; // IP value for the beginning of current instruction.
static ULONG SSRegisterTouched = FALSE; // TRUE if previous instruction changed the value of the SS register.
static USHORT Delta; // Increment value for string operations.
static ULONG ExitFlag; // If TRUE, the interpreter will exit
static ULONG GoFlag = FALSE; // TRUE if emulator is running. Set to FALSE on breakpoints.
static USHORT ExitSegment; // Segment of break point that causes the emulator to exit.
static USHORT ExitOffset; // Offset of break point that causes the emulator to exit.
static USHORT StopSegment; // Segment of break point.
static USHORT StopOffset; // Offset of break point.
static UCHAR MemoryArray[0x0800]; // 2K memory for INT vectors, BIOS data, temp code, and stack.
static X86BIOS_STATUS ErrorCode; // Reason for exiting emulator
/*++
Memory Access Functions:
The following functions are used to read and write values to and from
memory. Only part of the x86's 1MB address space is actually visible
to the emulator. The address range from 0000:0000 to 0000:03FF exists
to store INT vectors. The address range from 0000:0400 to 0000:04FF
exists for the BIOS data area in case the video bios wants to store
and retrieve value from here. The address range from 0000:0500 to
0000:0510 is an area where temporary code segements are build by the
emulator for entry and exit points. The address range from
0000:0510 to 0000:07FF is the video BIOS's stack area. The stack
pointer is initialized to the top of this area. The address range
from A000:0000 to D000:FFFF is visible to the emulator. Memory
accesses in this range perform memory read and write cycles to
ISA Memory. Memory read to unavailable regions always return 0,
and memory writes to unavailable regions perform no actions.
|----------------------------------------|
| |
| E000:0000 - F000:FFFF : Unavailable |
| |
|----------------------------------------|
| |
| A000:0000 - D000:FFFF : ISA Memory |
| |
|----------------------------------------|
| |
| 0000:0800 - 9000:FFFF : Unavailable |
| |
|----------------------------------------|
| |
| 0000:0510 - 0000:07FF : Stack |
| |
|----------------------------------------|
| |
| 0000:0500 - 0000:050F : Reserved |
| |
|----------------------------------------|
| |
| 0000:0400 - 0000:04FF : BIOS Data Area |
| |
|----------------------------------------|
| |
| 0000:0000 - 0000:03FF : INT Vectors |
| |
|----------------------------------------|
--*/
static UCHAR GetAbsoluteMem(
ULONG Offset
)
/*++
Routine Description:
This is the lowest level function for reading a byte from memory.
Arguments:
Offset - 20 bit value used to address a byte.
Return Value:
The byte stored at the address if that address is mapped.
Otherwise, return 0.
--*/
{
if (Offset>=0x0a0000 && Offset<0xe0000)
return(*(UCHAR *)(ISABaseAddress + Offset));
if (Offset<0x800)
return(*(UCHAR *)(VDMBaseAddress + Offset));
return(0);
}
static VOID PutAbsoluteMem(
ULONG Offset,
UCHAR Value
)
/*++
Routine Description:
This is the lowest level function for writing a byte to memory.
The byte is written to the address if that address is mapped.
Otherwise, no action is taken.
Arguments:
Offset - 20 bit value used to address a byte.
Value - The 8 bit data value that is to be written.
Return Value:
None
--*/
{
if (Offset>=0x0a0000 && Offset<0xe0000)
*(UCHAR *)(ISABaseAddress + Offset) = Value;
if (Offset<0x800)
*(UCHAR *)(VDMBaseAddress + Offset) = Value;
}
static UCHAR GetMem(
OPERAND *Operand,
ULONG Offset
)
/*++
Routine Description:
This function reads a byte from memory. Operand contains the
segment part and offset part of the address. If the processor is
in protected mode, the segment cache registers are used to compute
the address. If the processor is in real mode, the segment register
is shifted left four bits, and added to the offset.
Arguments:
Operand - Contains a memory reference in the MemorySegment and
MemoryOffset fields.
Offset - Additional offset from the memory location described in
Operand.
Return Value:
The byte read from the computed address.
--*/
{
if (msw & 1)
{
if (Operand->MemorySegment == (PVOID)(&CS))
return(GetAbsoluteMem(CSCacheRegister + Operand->MemoryOffset.X + Offset));
else if (Operand->MemorySegment == (PVOID)(&ES))
return(GetAbsoluteMem(ESCacheRegister + Operand->MemoryOffset.X + Offset));
else if (Operand->MemorySegment == (PVOID)(&SS))
return(GetAbsoluteMem(SSCacheRegister + Operand->MemoryOffset.X + Offset));
else if (Operand->MemorySegment == (PVOID)(&DS))
return(GetAbsoluteMem(DSCacheRegister + Operand->MemoryOffset.X + Offset));
else
DISPLAY("Protected mode GetMem() ERROR\n\r");
}
else
return(GetAbsoluteMem( (((*Operand->MemorySegment)<<4) + Operand->MemoryOffset.X + Offset)&0xfffff ));
}
static VOID PutMem(
OPERAND *Operand,
ULONG Offset,
UCHAR Value
)
/*++
Routine Description:
This function writes a byte to memory. Operand contains the
segment part and offset part of the address. If the processor is
in protected mode, the segment cache registers are used to compute
the address. If the processor is in real mode, the segment register
is shifted left four bits, and added to the offset.
Arguments:
Operand - Contains a memory reference in the MemorySegment and
MemoryOffset fields.
Offset - Additional offset from the memory location described in
Operand.
Value - 8 bit data value to be written to the computed address.
Return Value:
None.
--*/
{
if (msw & 1)
{
if (Operand->MemorySegment == (PVOID)(&CS))
PutAbsoluteMem(CSCacheRegister + Operand->MemoryOffset.X + Offset,Value);
else if (Operand->MemorySegment == (PVOID)(&ES))
PutAbsoluteMem(ESCacheRegister + Operand->MemoryOffset.X + Offset,Value);
else if (Operand->MemorySegment == (PVOID)(&SS))
PutAbsoluteMem(SSCacheRegister + Operand->MemoryOffset.X + Offset,Value);
else if (Operand->MemorySegment == (PVOID)(&DS))
PutAbsoluteMem(DSCacheRegister + Operand->MemoryOffset.X + Offset,Value);
else
DISPLAY("Protected mode PutMem() ERROR\n\r");
}
else
PutAbsoluteMem( (((*Operand->MemorySegment)<<4) + Operand->MemoryOffset.X + Offset)&0xfffff , Value);
}
static ULONG GetSegmentCacheRegister(
USHORT SegmentValue
)
/*++
Routine Description:
This function gets the 24 bit base address for a memory reference. The value
of the segment register is passed in. If the processor is in protected mode,
this value is used to lookup a 24 bit base address in the global descriptor
table. If the processor is in real mode, the segement register value is shifted
left 4 position and the 20 bit value is returned.
Arguments:
SegmentValue - 16 bit segment register value.
Return Value:
A 24 bit base address for a memory reference.
--*/
{
if (msw&1)
return(GetAbsoluteMem(gdtBase + SegmentValue + 2) | (GetAbsoluteMem(gdtBase + SegmentValue + 3) << 8) | (GetAbsoluteMem(gdtBase + SegmentValue + 4) << 16));
else
return((SegmentValue<<4)&0xfffff);
}
static UCHAR GetMemImmediate(
USHORT Segment,
USHORT Offset
)
/*++
Routine Description:
This function reads an 8 bit value from the memory location Segment:Offset.
Arguments:
Segment - 16 bit segment register value.
Offset - 16 bit offset within the segment defined by Segment.
Return Value:
The 8 bit value read from the memory location Segemnt:Offset.
--*/
{
if (msw&1)
return(GetAbsoluteMem( GetSegmentCacheRegister(Segment)+Offset ));
else
return(GetAbsoluteMem((GetSegmentCacheRegister(Segment)+Offset)&0xfffff));
}
static VOID PutMemImmediate(
USHORT Segment,
USHORT Offset,
UCHAR Value
)
/*++
Routine Description:
This function writes an 8 bit value to the memory location Segment:Offset.
Arguments:
Segment - 16 bit segment register value.
Offset - 16 bit offset within the segment defined by Segment.
Value - 8 bit value to write to the memory location Segment:Offset.
Return Value:
None.
--*/
{
if (msw&1)
PutAbsoluteMem(GetSegmentCacheRegister(Segment)+Offset,Value);
else
PutAbsoluteMem((GetSegmentCacheRegister(Segment)+Offset)&0xfffff,Value);
}
static UCHAR CodeMem(
USHORT Offset
)
/*++
Routine Description:
This function reads an 8 bit value from the code area. The location
read is CS:Offset.
Arguments:
Offset - 16 bit offset within the current code segment.
Return Value:
The 8 bit value read from the code area.
--*/
{
return(GetAbsoluteMem((CSCacheRegister + Offset)&0xfffff));
}
static UCHAR GetStackMem(
USHORT Offset
)
/*++
Routine Description:
This function reads an 8 bit value from the stack. The location
read is SS:Offset.
Arguments:
Offset - 16 bit offset within the current stack segment.
Return Value:
The 8 bit value read from the stack.
--*/
{
return(GetAbsoluteMem((SSCacheRegister + Offset)&0xfffff));
}
static VOID PutStackMem(
USHORT Offset,
UCHAR Value
)
/*++
Routine Description:
This function stores a byte onto the stack. The location written is
SS:Offset.
Arguments:
Offset - 16 bit offset within the current stack segment.
Value - 8 bit value to be stored onto the stack.
Return Value:
None.
--*/
{
PutAbsoluteMem((SSCacheRegister + Offset)&0xfffff,Value);
}
//
// Debugging functions
//
#ifdef X86DEBUG
static VOID PrintProcessorState(UCHAR *S)
{
UCHAR T[256];
ULONG CR;
ULONG SR;
sprintf(S,"AX=%04X BX=%04X CX=%04X DX=%04X SP=%04X BP=%04X SI=%04X DI=%04X\n\rDS=%04X ES=%04X SS=%04X CS=%04X IP=%04X ",
AX,BX,CX,DX,SP,BP,SI,DI,DS,ES,SS,CS,CurrentIP.X);
if (OF) strcat(S,"OV "); else strcat(S,"NV ");
if (DF) strcat(S,"DN "); else strcat(S,"UP ");
if (IF) strcat(S,"EI "); else strcat(S,"DI ");
if (SF) strcat(S,"NG "); else strcat(S,"PL ");
if (ZF) strcat(S,"ZR "); else strcat(S,"NZ ");
if (AF) strcat(S,"AC "); else strcat(S,"NA ");
if (PF) strcat(S,"PE "); else strcat(S,"PO ");
if (CF) strcat(S,"CY\n\r"); else strcat(S,"NC\n\r");
sprintf(T,"EAX=%08X EBX=%08X ECX=%08X EDX=%08X\n\rESP=%08X EBP=%08X ESI=%08X EDI=%08X\n\r",
EAX,EBX,ECX,EDX,ESP,EBP,ESI,EDI);
strcat(S,T);
sprintf(T,"MSW=%04X GDTBase=%06X GDTLimit=%04X IDTBase=%06X IDTLimit=%04X\n\r",
msw,gdtBase,gdtLimit,idtBase,idtLimit);
strcat(S,T);
sprintf(T,"DSCache=%04X ESCache=%04X SSCache=%04X CSCache=%04X\n\r",
DSCacheRegister,ESCacheRegister,SSCacheRegister,CSCacheRegister);
strcat(S,T);
CR = GetCauseRegister();
SR = GetStatusRegister();
sprintf(T,"CR = %08X SR = %08X\n\r",CR,SR);
strcat(S,T);
}
/***************************************************************************/
static VOID PrintMemorySegmentName(OPERAND *Operand,UCHAR *S)
{
strcpy(S,"");
switch (Operand->OperandType)
{
case Memory8Operand :
case Memory16Operand : if (Operand->MemorySegment == (PVOID)(&CS))
sprintf(S,"CS");
else if (Operand->MemorySegment == (PVOID)(&ES))
sprintf(S,"ES");
else if (Operand->MemorySegment == (PVOID)(&SS))
sprintf(S,"SS");
else if (Operand->MemorySegment == (PVOID)(&DS))
sprintf(S,"DS");
break;
default : ERROR("PrintMemorySegmentName()\n\r");
break;
}
}
/***************************************************************************/
static VOID PrintMemoryAccessSize(OPERAND *Operand,UCHAR *S)
{
strcpy(S,"");
switch (Operand->OperandType)
{
case Memory8Operand : sprintf(S,"BYTE PTR");
break;
case Memory16Operand : sprintf(S,"WORD PTR");
break;
default : ERROR("PrintMemoryAccessSize()\n\r");
break;
}
}
/***************************************************************************/
static VOID PrintOperandName(OPERAND *Operand,UCHAR *S)
{
strcpy(S,"");
switch (Operand->OperandType)
{
case Register8Operand : if (Operand->Register8 == (PVOID)(&AL))
sprintf(S,"AL");
else if (Operand->Register8 == (PVOID)(&AH))
sprintf(S,"AH");
else if (Operand->Register8 == (PVOID)(&BL))
sprintf(S,"BL");
else if (Operand->Register8 == (PVOID)(&BH))
sprintf(S,"BH");
else if (Operand->Register8 == (PVOID)(&CL))
sprintf(S,"CL");
else if (Operand->Register8 == (PVOID)(&CH))
sprintf(S,"CH");
else if (Operand->Register8 == (PVOID)(&DL))
sprintf(S,"DL");
else if (Operand->Register8 == (PVOID)(&DH))
sprintf(S,"DH");
break;
case Register16Operand : if (Operand->Register16 == (PVOID)(&AX))
sprintf(S,"AX");
else if (Operand->Register16 == (PVOID)(&BX))
sprintf(S,"BX");
else if (Operand->Register16 == (PVOID)(&CX))
sprintf(S,"CX");
else if (Operand->Register16 == (PVOID)(&DX))
sprintf(S,"DX");
else if (Operand->Register16 == (PVOID)(&BP))
sprintf(S,"BP");
else if (Operand->Register16 == (PVOID)(&SP))
sprintf(S,"SP");
else if (Operand->Register16 == (PVOID)(&SI))
sprintf(S,"SI");
else if (Operand->Register16 == (PVOID)(&DI))
sprintf(S,"DI");
else if (Operand->Register16 == (PVOID)(&CS))
sprintf(S,"CS");
else if (Operand->Register16 == (PVOID)(&ES))
sprintf(S,"ES");
else if (Operand->Register16 == (PVOID)(&SS))
sprintf(S,"SS");
else if (Operand->Register16 == (PVOID)(&DS))
sprintf(S,"DS");
else if (Operand->Register16 == (PVOID)(&IP))
sprintf(S,"IP");
break;
case Memory8Operand : sprintf(S,"[%04X]",Operand->MemoryOffset.X);
break;
case Memory16Operand : sprintf(S,"[%04X]",Operand->MemoryOffset.X);
break;
case Immediate8Operand : sprintf(S,"%02X",Operand->Immediate8.L);
break;
case Immediate16Operand : sprintf(S,"%04X",Operand->Immediate16.X);
break;
case ShortLabelOperand : sprintf(S,"%02X",Operand->ShortLabel.L);
break;
case Immediate32Operand : sprintf(S,"%04X:%04X",Operand->Immediate32Segment.X,Operand->Immediate32Offset.X);
break;
}
}
/***************************************************************************/
static VOID PrintOperandValue(OPERAND *Operand,UCHAR *S)
{
strcpy(S,"");
switch (Operand->OperandType)
{
case Register8Operand : if (Operand->Register8 == (PVOID)(&AL))
sprintf(S,"%02X",AL);
else if (Operand->Register8 == (PVOID)(&AH))
sprintf(S,"%02X",AH);
else if (Operand->Register8 == (PVOID)(&BL))
sprintf(S,"%02X",BL);
else if (Operand->Register8 == (PVOID)(&BH))
sprintf(S,"%02X",BH);
else if (Operand->Register8 == (PVOID)(&CL))
sprintf(S,"%02X",CL);
else if (Operand->Register8 == (PVOID)(&CH))
sprintf(S,"%02X",CH);
else if (Operand->Register8 == (PVOID)(&DL))
sprintf(S,"%02X",DL);
else if (Operand->Register8 == (PVOID)(&DH))
sprintf(S,"%02X",DH);
break;
case Register16Operand : if (Operand->Register16 == (PVOID)(&AX))
sprintf(S,"%04X",AX);
else if (Operand->Register16 == (PVOID)(&BX))
sprintf(S,"%04X",BX);
else if (Operand->Register16 == (PVOID)(&CX))
sprintf(S,"%04X",CX);
else if (Operand->Register16 == (PVOID)(&DX))
sprintf(S,"%04X",DX);
else if (Operand->Register16 == (PVOID)(&BP))
sprintf(S,"%04X",BP);
else if (Operand->Register16 == (PVOID)(&SP))
sprintf(S,"%04X",SP);
else if (Operand->Register16 == (PVOID)(&SI))
sprintf(S,"%04X",SI);
else if (Operand->Register16 == (PVOID)(&DI))
sprintf(S,"%04X",DI);
else if (Operand->Register16 == (PVOID)(&CS))
sprintf(S,"%04X",CS);
else if (Operand->Register16 == (PVOID)(&ES))
sprintf(S,"%04X",ES);
else if (Operand->Register16 == (PVOID)(&SS))
sprintf(S,"%04X",SS);
else if (Operand->Register16 == (PVOID)(&DS))
sprintf(S,"%04X",DS);
else if (Operand->Register16 == (PVOID)(&IP))
sprintf(S,"%04X",IP);
break;
case Memory8Operand : sprintf(S,"%02X",(ULONG)(GetMem(Operand,0)));
break;
case Memory16Operand : sprintf(S,"%04X",(ULONG)(GetMem(Operand,0)) | (ULONG)(GetMem(Operand,1)<<8));
break;
case Immediate8Operand : sprintf(S,"%02X",Operand->Immediate8.L);
break;
case Immediate16Operand : sprintf(S,"%04X",Operand->Immediate16.X);
break;
case ShortLabelOperand : sprintf(S,"%02X",Operand->ShortLabel.L);
break;
case Immediate32Operand : sprintf(S,"%04X:%04X",Operand->Immediate32Segment.X,Operand->Immediate32Offset.X);
break;
}
}
#endif
static ULONG GetOperand(
OPERAND *Operand,
ULONG Offset
)
/*++
Routine Description:
This function is used to retrieve a value from either a register, a memory
location, or an immediate value. The OperandType field of Operand contains
the operand's type.
Arguments:
*Operand - Operand where Value is to be retrieved.
Offset - For memory operands, Offset is the number of bytes forward of
the effective address that Value is to be retrieved.
Return Value:
The 8 or 16 bit value retrieved from Operand.
--*/
{
if (Offset!=0)
if (Operand->OperandType!=Memory8Operand && Operand->OperandType!=Memory16Operand)
{
ERROR("GetOperand()\n\r");
return(0);
}
switch (Operand->OperandType)
{
case Register8Operand : return((ULONG)(*(UCHAR *)(Operand->Register8)));
break;
case Register16Operand : return((ULONG)(*(USHORT *)(Operand->Register16)));
break;
case Memory8Operand : return((ULONG)(GetMem(Operand,Offset)));
break;
case Memory16Operand : return((ULONG)(GetMem(Operand,Offset) | (GetMem(Operand,Offset+1) << 8)));
break;
case Immediate8Operand : return((ULONG)(Operand->Immediate8.L));
break;
case Immediate16Operand : return((ULONG)(Operand->Immediate16.X));
break;
case ShortLabelOperand : return((ULONG)(Operand->ShortLabel.X));
break;
case Immediate32Operand : return((ULONG)(Operand->Immediate32Segment.X<<16 | Operand->Immediate32Offset.X));
break;
default : ERROR("GetOperand()\n\r");
return(0);
break;
}
}
static VOID PutOperand(
OPERAND *Operand,
ULONG Offset,
ULONG Value
)
/*++
Routine Description:
This function is used to store a value to either a register, or a memory
location. The OperandType field of Operand contains the operand's type.
Arguments:
*Operand - Operand where Value is to be written.
Offset - For memory operands, Offset is the number of bytes forward of
the effective address that Value is to be written.
Value - 8 or 16 bit immediate value that is to be written to Operand.
Return Value:
None.
--*/
{
if (Offset!=0)
if (Operand->OperandType!=Memory8Operand && Operand->OperandType!=Memory16Operand)
{
ERROR("PutOperand()\n\r");
return;
}
switch (Operand->OperandType)
{
case Register8Operand : *(Operand->Register8) = Value;
break;
case Register16Operand : *(Operand->Register16) = Value;
if (Operand->Register16 == (PVOID)(&CS))
CSCacheRegister = GetSegmentCacheRegister(CS);
else if (Operand->Register16 == (PVOID)(&ES))
ESCacheRegister = GetSegmentCacheRegister(ES);
else if (Operand->Register16 == (PVOID)(&SS))
{
SSCacheRegister = GetSegmentCacheRegister(SS);
SSRegisterTouched = TRUE;
}
else if (Operand->Register16 == (PVOID)(&DS))
DSCacheRegister = GetSegmentCacheRegister(DS);
break;
case Memory8Operand : PutMem(Operand,Offset,Value);
break;
case Memory16Operand : PutMem(Operand,Offset+0,Value);
PutMem(Operand,Offset+1,Value>>8);
break;
case Immediate8Operand : Operand->Immediate8.L = Value;
break;
case Immediate16Operand : Operand->Immediate16.X = Value;
break;
case ShortLabelOperand : Operand->ShortLabel.L = Value;
if (Operand->ShortLabel.L & 0x80)
Operand->ShortLabel.H = 0xff;
else
Operand->ShortLabel.L = 0x00;
break;
case Immediate32Operand : Operand->Immediate32Segment.X = Value >> 16;
Operand->Immediate32Offset.X = Value;
break;
default : ERROR("PutOperand()\n\r");
break;
}
}
/*++
Address Decoding Support Functions:
The following functions are used by the address decoding functions
to decode operands.
--*/
static VOID GetAddressModeByte()
/*++
Routine Description:
This function parses the address mode byte from the instruction currently
being decoded. The mod, reg, and r/m bit fields are also extracted from
the address mode byte, so they can be used by the address decoding
functions.
Arguments:
None.
Return Value:
None.
--*/
{
AddressModeByte = CodeMem(IP); IP++;
mod = (AddressModeByte >> 6) & 0x03;
reg = (AddressModeByte >> 3) & 0x07;
r_m = (AddressModeByte >> 0) & 0x07;
}
USHORT *pGetCurrentSegment(
USHORT *DefaultSegmentRegister
)
/*++
Routine Description:
This function returns the segment register that is active for
the instruction that us currently being decoded. The default
segement register for the address mode being parse is passed
into this function. If there are no segement overide prefix
instructions affecting this instruction, then the default
segement register will be returned. Otherwise, the segement
regeister referenced in the segment overide prefix instruction
will be returned.
Arguments:
DefaultSegmentRegister - The default segment register for the
address mode being decoded.
Return Value:
The segement register that is valid for the instruction that
is currently being decoded.
--*/
{
if (SegmentOveridePrefix)
return(OverideSegmentRegister);
else
return(DefaultSegmentRegister);
}
static VOID pGetRegister8Operand(
OPERAND *Operand,UCHAR reg
)
/*++
Routine Description:
This function builds an 8 bit general purpose register operand.
Arguments:
*Operand - Used to return the 8 bit genral purpose register operand.
reg - 3 bit value used to determine which general purpose register
is being referenced.
Return Value:
None.
--*/
{
Operand->OperandType = Register8Operand;
switch (reg)
{
case 0 : Operand->Register8 = &AL;
break;
case 1 : Operand->Register8 = &CL;
break;
case 2 : Operand->Register8 = &DL;
break;
case 3 : Operand->Register8 = &BL;
break;
case 4 : Operand->Register8 = &AH;
break;
case 5 : Operand->Register8 = &CH;
break;
case 6 : Operand->Register8 = &DH;
break;
case 7 : Operand->Register8 = &BH;
break;
}
}
static VOID pGetRegister16Operand(
OPERAND *Operand,
UCHAR reg
)
/*++
Routine Description:
This function builds a 16 bit general purpose register operand.
Arguments:
*Operand - Used to return the 16 bit genral purpose register operand.
reg - 3 bit value used to determine which general purpose register
is being referenced.
Return Value:
None.
--*/
{
Operand->OperandType = Register16Operand;
switch (reg)
{
case 0 : Operand->Register16 = &AX;
break;
case 1 : Operand->Register16 = &CX;
break;
case 2 : Operand->Register16 = &DX;
break;
case 3 : Operand->Register16 = &BX;
break;
case 4 : Operand->Register16 = &SP;
break;
case 5 : Operand->Register16 = &BP;
break;
case 6 : Operand->Register16 = &SI;
break;
case 7 : Operand->Register16 = &DI;
break;
}
}
static VOID pGetSegmentRegisterOperand(
OPERAND *Operand,
UCHAR reg
)
/*++
Routine Description:
This function builds a segment register operand.
Arguments:
*Operand - Used to return the segment register operand.
reg - A 2 bit value used to determine which segment register is
being referenced.
Return Value:
None.
--*/
{
if (reg>=4)
{
ERROR("GetSegmentRegisterOperand()\n\r");
return;
}
Operand->OperandType = Register16Operand;
switch(reg)
{
case 0 : Operand->Register16 = &ES;
break;
case 1 : Operand->Register16 = &CS;
break;
case 2 : Operand->Register16 = &SS;
break;
case 3 : Operand->Register16 = &DS;
break;
}
}
static VOID pGetMemoryOperand(
OPERAND *Operand
)
/*++
Routine Description:
This function examines the bit fields from the address mode byte
and computes the effective address of a memory reference. The
mod field is used to parse the size and type of displacement from
the instruction, and the r_m field is used to determine which
registers are combined with the displacement to form the effective
address of the memory reference.
Arguments:
*Operand - The effective address of the memory is returned in this
parameter.
Return Value:
None.
--*/
{
REGISTER32 disp;
switch (mod)
{
case 0 : if (r_m==6)
{
disp.L = CodeMem(IP); IP++;
disp.H = CodeMem(IP); IP++;
}
else
disp.X = 0;
break;
case 1 : disp.L = CodeMem(IP); IP++;
if (disp.L & 0x80)
disp.H = 0xff;
else
disp.H = 0x00;
break;
case 2 : disp.L = CodeMem(IP); IP++;
disp.H = CodeMem(IP); IP++;
break;
}
switch (r_m)
{
case 0 : Operand->MemorySegment = pGetCurrentSegment(&DS);
Operand->MemoryOffset.X = BX + SI + disp.X;
break;
case 1 : Operand->MemorySegment = pGetCurrentSegment(&DS);
Operand->MemoryOffset.X = BX + DI + disp.X;
break;
case 2 : Operand->MemorySegment = pGetCurrentSegment(&SS);
Operand->MemoryOffset.X = BP + SI + disp.X;
break;
case 3 : Operand->MemorySegment = pGetCurrentSegment(&SS);
Operand->MemoryOffset.X = BP + DI + disp.X;
break;
case 4 : Operand->MemorySegment = pGetCurrentSegment(&DS);
Operand->MemoryOffset.X = SI + disp.X;
break;
case 5 : Operand->MemorySegment = pGetCurrentSegment(&DS);
Operand->MemoryOffset.X = DI + disp.X;
break;
case 6 : if (mod==0)
{
Operand->MemorySegment = pGetCurrentSegment(&DS);
Operand->MemoryOffset.X = disp.X;
}
else
{
Operand->MemorySegment = pGetCurrentSegment(&SS);
Operand->MemoryOffset.X = BP + disp.X;
}
break;
case 7 : Operand->MemorySegment = pGetCurrentSegment(&DS);
Operand->MemoryOffset.X = BX + disp.X;
break;
}
}
/*++
Address Decoding Functions:
The following functions are used to decode the operands from an
instruction. They all have an OPERAND variable as a parameter.
The decoded operand is returned in the OPERAND variable.
static VOID GetMemory8OrRegister8Operand(OPERAND *Operand)
Decodes an 8 bit general purpose register or a BYTE PTR memory operand
from an instruction.
static VOID GetMemory16OrRegister16Operand(OPERAND *Operand)
Decodes a 16 bit general purpose register or a WORD PTR memory operand
from an instruction.
static VOID GetRegister8Operand(OPERAND *Operand)
Decodes an 8 bit general purpose register from an instruction.
static VOID GetRegister16Operand(OPERAND *Operand)
Decodes a 16 bit general purpose register from an instruction.
static VOID GetSegmentRegisterOperand(OPERAND *Operand)
Decodes a 16 bit segment register from an instruction.
static VOID GetEmbeddedRegister8Operand(OPERAND *Operand)
Decodes an 8 bit general purpose register from an instruction. The
register number is embedded in 3 bits of the first byte of the
instruction.
static VOID GetEmbeddedRegister16Operand(OPERAND *Operand)
Decodes a 16 bit general purpose register from an instruction. The
register number is embedded in 3 bits of the first byte of the
instruction.
static VOID GetAccumulator8Operand(OPERAND *Operand)
Decodes the 8 bit general purpose register AL.
static VOID GetAccumulator16Operand(OPERAND *Operand)
Decodes the 16 bit general purpose register AX.
static VOID GetImmediate8Operand(OPERAND *Operand)
Decodes an 8 bit immediate value from an instruction.
static VOID GetImmediateSignExtend8Operand(OPERAND *Operand)
Decodes a 16 bit immediate value from an instruction. Only an 8 bit
value is encoded in the instruction. The 8 bit value is sign extended
to form a 16 bit value.
static VOID GetImmediate16Operand(OPERAND *Operand)
Decodes a 16 bot immediate value from an instruction.
static VOID GetShortLabelOperand(OPERAND *Operand)
Decodes an 8 bit signed immediate value from an instruction. This
operand is type is only used by branching instructions.
static VOID GetImmediate32Operand(OPERAND *Operand)
Decodes a 32 bit immediate value from an instruction. This is used
as a 16 bit segment and a 16 bit offset to reference a memory location.
static VOID GetMemory8Operand(OPERAND *Operand)
Decodes an 8 bit BYTE PTR memory operand from an instruction.
static VOID GetMemory16Operand(OPERAND *Operand)
Decodes an 16 bit WORD PTR memory operand from an instruction.
static VOID GetConstantOneOperand(OPERAND *Operand)
Decodes a constant operand whose value is 1.
static VOID GetRegisterCLOperand(OPERAND *Operand)
Decodes the 8 bit general purpose register CL.
static VOID GetRegisterDXOperand(OPERAND *Operand)
Decodes the 16 bit general purpose register DX.
static VOID GetRegisterESOperand(OPERAND *Operand)
Decodes the 16 bit segment register ES.
static VOID GetRegisterCSOperand(OPERAND *Operand)
Decodes the 16 bit segment register CS.
static VOID GetRegisterSSOperand(OPERAND *Operand)
Decodes the 16 bit segment register SS.
static VOID GetRegisterDSOperand(OPERAND *Operand)
Decodes the 16 bit segment register DS.
static VOID GetString8DSSIOperand(OPERAND *Operand)
Decodes the memory location for a string instruction. The operand
will be an 8 bit BYTE PTR memory location whose address is DS:SI.
static VOID GetString16DSSIOperand(OPERAND *Operand)
Decodes the memory location for a string instruction. The operand
will be an 16 bit WORD PTR memory location whose address is DS:SI.
static VOID GetString8ESDIOperand(OPERAND *Operand)
Decodes the memory location for a string instruction. The operand
will be an 8 bit BYTE PTR memory location whose address is ES:DI.
static VOID GetString16ESDIOperand(OPERAND *Operand)
Decodes the memory location for a string instruction. The operand
will be an 16 bit WORD PTR memory location whose address is ES:DI.
static VOID NullFunction()
This function is called when an instruction contains less than two
operand. If and instruction has no operands, then this function
would be called twice. Once for the left operand, and once for the
right operand.
--*/
/***************************************************************************/
static VOID GetMemory8OrRegister8Operand(OPERAND *Operand)
{
if (mod==3)
pGetRegister8Operand(Operand,r_m);
else
{
Operand->OperandType = Memory8Operand;
pGetMemoryOperand(Operand);
}
}
/***************************************************************************/
static VOID GetMemory16OrRegister16Operand(OPERAND *Operand)
{
if (mod==3)
pGetRegister16Operand(Operand,r_m);
else
{
Operand->OperandType = Memory16Operand;
pGetMemoryOperand(Operand);
}
}
/***************************************************************************/
static VOID GetRegister8Operand(OPERAND *Operand)
{
pGetRegister8Operand(Operand,reg);
}
/***************************************************************************/
static VOID GetRegister16Operand(OPERAND *Operand)
{
pGetRegister16Operand(Operand,reg);
}
/***************************************************************************/
static VOID GetSegmentRegisterOperand(OPERAND *Operand)
{
pGetSegmentRegisterOperand(Operand,reg);
}
/***************************************************************************/
static VOID GetEmbeddedRegister8Operand(OPERAND *Operand)
{
pGetRegister8Operand(Operand,OperationCodeByte & 0x07);
}
/***************************************************************************/
static VOID GetEmbeddedRegister16Operand(OPERAND *Operand)
{
pGetRegister16Operand(Operand,OperationCodeByte & 0x07);
}
/***************************************************************************/
static VOID GetAccumulator8Operand(OPERAND *Operand)
{
pGetRegister8Operand(Operand,0);
}
/***************************************************************************/
static VOID GetAccumulator16Operand(OPERAND *Operand)
{
pGetRegister16Operand(Operand,0);
}
/***************************************************************************/
static VOID GetImmediate8Operand(OPERAND *Operand)
{
Operand->OperandType = Immediate8Operand;
Operand->Immediate8.L = CodeMem(IP); IP++;
}
/***************************************************************************/
static VOID GetImmediateSignExtend8Operand(OPERAND *Operand)
{
Operand->OperandType = Immediate16Operand;
Operand->Immediate16.L = CodeMem(IP); IP++;
if (Operand->Immediate16.L & 0x80)
Operand->Immediate16.H = 0xff;
else
Operand->Immediate16.H = 0x00;
}
/***************************************************************************/
static VOID GetImmediate16Operand(OPERAND *Operand)
{
Operand->OperandType = Immediate16Operand;
Operand->Immediate16.L = CodeMem(IP); IP++;
Operand->Immediate16.H = CodeMem(IP); IP++;
}
/***************************************************************************/
static VOID GetShortLabelOperand(OPERAND *Operand)
{
Operand->OperandType = ShortLabelOperand;
Operand->ShortLabel.L = CodeMem(IP); IP++;
if (Operand->ShortLabel.L & 0x80)
Operand->ShortLabel.H = 0xff;
else
Operand->ShortLabel.H = 0x00;
}
/***************************************************************************/
static VOID GetImmediate32Operand(OPERAND *Operand)
{
Operand->OperandType = Immediate32Operand;
Operand->Immediate32Offset.L = CodeMem(IP); IP++;
Operand->Immediate32Offset.H = CodeMem(IP); IP++;
Operand->Immediate32Segment.L = CodeMem(IP); IP++;
Operand->Immediate32Segment.H = CodeMem(IP); IP++;
}
/***************************************************************************/
static VOID GetMemory8Operand(OPERAND *Operand)
{
Operand->OperandType = Memory8Operand;
Operand->MemorySegment = pGetCurrentSegment(&DS);
Operand->MemoryOffset.L = CodeMem(IP); IP++;
Operand->MemoryOffset.H = CodeMem(IP); IP++;
}
/***************************************************************************/
static VOID GetMemory16Operand(OPERAND *Operand)
{
Operand->OperandType = Memory16Operand;
Operand->MemorySegment = pGetCurrentSegment(&DS);
Operand->MemoryOffset.L = CodeMem(IP); IP++;
Operand->MemoryOffset.H = CodeMem(IP); IP++;
}
/***************************************************************************/
static VOID GetConstantOneOperand(OPERAND *Operand)
{
Operand->OperandType = Immediate8Operand;
Operand->Immediate8.L = 1;
}
/***************************************************************************/
static VOID GetRegisterCLOperand(OPERAND *Operand)
{
pGetRegister8Operand(Operand,1);
}
/***************************************************************************/
static VOID GetRegisterDXOperand(OPERAND *Operand)
{
pGetRegister16Operand(Operand,2);
}
/***************************************************************************/
static VOID GetRegisterESOperand(OPERAND *Operand)
{
pGetSegmentRegisterOperand(Operand,0);
}
/***************************************************************************/
static VOID GetRegisterCSOperand(OPERAND *Operand)
{
pGetSegmentRegisterOperand(Operand,1);
}
/***************************************************************************/
static VOID GetRegisterSSOperand(OPERAND *Operand)
{
pGetSegmentRegisterOperand(Operand,2);
}
/***************************************************************************/
static VOID GetRegisterDSOperand(OPERAND *Operand)
{
pGetSegmentRegisterOperand(Operand,3);
}
/***************************************************************************/
static VOID GetString8DSSIOperand(OPERAND *Operand)
{
Operand->OperandType = Memory8Operand;
Operand->MemorySegment = pGetCurrentSegment(&DS);
Operand->MemoryOffset.X = SI;
if (DF)
Delta = 0xFFFF;
else
Delta = 1;
}
/***************************************************************************/
static VOID GetString16DSSIOperand(OPERAND *Operand)
{
Operand->OperandType = Memory16Operand;
Operand->MemorySegment = pGetCurrentSegment(&DS);
Operand->MemoryOffset.X = SI;
if (DF)
Delta = 0xFFFE;
else
Delta = 2;
}
/***************************************************************************/
static VOID GetString8ESDIOperand(OPERAND *Operand)
{
Operand->OperandType = Memory8Operand;
Operand->MemorySegment = &ES;
Operand->MemoryOffset.X = DI;
if (DF)
Delta = 0xFFFF;
else
Delta = 1;
}
/***************************************************************************/
static VOID GetString16ESDIOperand(OPERAND *Operand)
{
Operand->OperandType = Memory16Operand;
Operand->MemorySegment = &ES;
Operand->MemoryOffset.X = DI;
if (DF)
Delta = 0xFFFE;
else
Delta = 2;
}
/***************************************************************************/
static VOID NullFunction()
{
}
/***************************************************************************/
/*++
Flag Functions:
The following functions compute the new values for the FLAGS register
after an instruction has been executed. The Sign flag, Zero flag,
and Parity flag only depend on the value of the result. However,
the Overflow flag, Carry flag, and Auxillary carry flag depend on the
values of the left and right operand as well os the result and weather
the operation involved addition or subtraction.
--*/
static VOID ComputeFlags8(
ULONG Result
)
/*++
Routine Description:
This function computes the Sign flag, Zero flag, and Parity flag for the
8 bit result operand Result. If bit 7 is set, the Sign flag is true,
otherwise it is false. If all the bits are zero, the Zero flag is true,
otherwise it is false. The Parity flag is true if there are an even
number of bits set in the 8 bit quantity. ParityTable is used to speed
up this computation. Each entry in ParityTable contains the number of
bits set for a value that is equivalent to the index. ParityTable is 16
entries long, so it can handle 4 bit values. Two look ups are made for
bits 0:3 of Result and for bit 4:7 of result. These values are added
to get to total number of bits sets in the 8 bit Result operand. If this
sum is an even number, the Parity flag is set to true, otherwise it is
false.
Arguments:
Result - 8 bit result operand used to generate flag values.
Return Value:
None.
--*/
{
SF = (Result>>7) & 1;
ZF = (Result & 0xff) == 0x00;
if (((ParityTable[Result&0x0f] + ParityTable[(Result>>4) & 0x0f]) & 0x01) == 0)
PF = 1;
else
PF = 0;
}
static VOID ComputeFlags16(
ULONG Result
)
/*++
Routine Description:
This function computes the Sign flag, Zero flag, and Parity flag for the
16 bit result operand Result. If bit 15 is set, the Sign flag is true,
otherwise it is false. If all the bits are zero, the Zero flag is true,
otherwise it is false. The Parity flag is true if there are an even
number of bits set in the lower 8 bits of Result. ParityTable is used to
speed up this computation. Each entry in ParityTable contains the number
of bits set for a value that is equivalent to the index. ParityTable is
16 entries long, so it can handle 4 bit values. Two look ups are made for
bits 0:3 of Result and for bit 4:7 of result. These values are added
to get to total number of bits sets in the lower 8 bits of Result. If this
sum is an even number, the Parity flag is set to true, otherwise it is
false.
Arguments:
Result - 16 bit result operand used to generate flag values.
Return Value:
None.
--*/
{
SF = (Result>>15) & 1;
ZF = (Result & 0xffff) == 0x0000;
if (((ParityTable[Result&0x0f] + ParityTable[(Result>>4) & 0x0f]) & 0x01) == 0)
PF = 1;
else
PF = 0;
}
static VOID ComputeSignZeroParityFlags(
ULONG Result
)
/*++
Routine Description:
This function computes the Sign flag, Zero flag, and Parity flag for
the result operand of an instruction. The result operand may be either
an 8 bit quntity or a 16 bit quantity. The OperationCodeByte is
evaluated to determine the size of the operation, and the approriate
flag computation function is called.
Arguments:
Result - 8 or 16 bit result operand used to compute flag values.
Return Value:
None.
--*/
{
if (OperationCodeByte & 0x01) // 16 Bit Operation
ComputeFlags16(Result);
else // 8 Bit Operation
ComputeFlags8(Result);
}
static VOID ComputeAllFlags(
ULONG Left,
ULONG Right,
ULONG *Result,
ULONG AddFlag,
ULONG CarryIn
)
/*++
Routine Description:
This function computes all the flags that can be affected by an ALU
instruction. All instructions that use either an addition or a
subtraction operation that affect the state of the processors
flags use this function to perform the addition or subtraction
operation as well as all the flag computations.
Arguments:
Left - The 8 or 16 bit value for the left operand of the instruction,
Right - The 8 or 16 bit value for the right operand of the instruction.
*Result - The 8 or 16 bit Result operand for the instruction
AddFlag - Flag that is either ADDOPERATION or SUBOPERATION
CarryIn - Value of Carry flag before the instruction is executed.
Return Value:
The result of the operation is resturned in *Result..
--*/
{
ULONG SmallResult; // Use to compute Auxillary Carry flag.
if (AddFlag==ADDOPERATION)
{
*Result = Left + Right + CarryIn;
SmallResult = (Left & 0x0f) + (Right & 0x0f) + CarryIn;
}
else
{
*Result = Left - Right - CarryIn;
SmallResult = (Left & 0x0f) - (Right & 0x0f) - CarryIn;
Right = (~Right) + 1; // Right = (-Right);
}
if (OperationCodeByte & 0x01) // 16 Bit Operation
{
if ( (Left&0x8000) == (Right&0x8000) && (Left&0x8000)!=(*Result&0x8000) )
OF = 1;
else
OF = 0;
if (*Result & 0x10000)
CF = 1;
else
CF = 0;
if (SmallResult & 0x10)
AF = 1;
else
AF = 0;
ComputeFlags16(*Result); // Compute Sign, Zero, and Parity flags.
}
else // 8 Bit Operation
{
if ( (Left&0x80) == (Right&0x80) && (Left&0x80)!=(*Result&0x80) )
OF = 1;
else
OF = 0;
if (*Result & 0x100)
CF = 1;
else
CF = 0;
if (SmallResult & 0x10)
AF = 1;
else
AF = 0;
ComputeFlags8(*Result); // Compute Sign, Zero, and Parity flags.
}
}
static VOID
GenerateINT(
UCHAR Type
)
/*++
Routine Description:
This function forces and INT vector call to be made. The flags are saved
onto the stack along with the current values of CS and IP. CS and IP are
then initialized to the vector for the INT Type being generated.
Arguments:
Type - 8 bit value for the type of software interrupt to generate.
Return Value:
None.
--*/
{
if (SegmentOveridePrefix==TRUE)
IP--;
if (RepeatPrefix==TRUE)
IP--;
if (LockPrefix==TRUE)
IP--;
#ifdef X86DEBUG1
AddressTrace[AddressTracePosition] = CS<<16 | IP;
AddressTracePosition = (AddressTracePosition + 1) % ADDRESSTRACESIZE;
#endif
SP = SP - 2;
PutStackMem(SP+0,Flags.L & 0xd7);
PutStackMem(SP+1,Flags.H & 0x0f);
IF = 0;
TF = 0;
SP = SP - 2;
PutStackMem(SP+0,cs.L);
PutStackMem(SP+1,cs.H);
SP = SP - 2;
PutStackMem(SP+0,ip.L);
PutStackMem(SP+1,ip.H);
cs.L = GetMemImmediate(0,Type*4+2);
cs.H = GetMemImmediate(0,Type*4+3);
CSCacheRegister = GetSegmentCacheRegister(CS);
ip.L = GetMemImmediate(0,Type*4+0);
ip.H = GetMemImmediate(0,Type*4+1);
#ifdef X86DEBUG1
AddressTrace[AddressTracePosition] = CS<<16 | IP;
AddressTracePosition = (AddressTracePosition + 1) % ADDRESSTRACESIZE;
#endif
}
/*++
Instruction Functions:
The following functions perform the actions for each of the instructions
in the 80286 instruction set. The register macros defined at the top
of this file make these functions very readable. See an 80286 assembly
language book for a description of each of these instructions.
--*/
/***************************************************************************/
static VOID InstInvalid()
{
PRINT4("Invalid Instruction %04X:%04X %02X\n\r",CS,IP,OperationCodeByte);
DISPLAY(PrintMessage);
ErrorCode = x86BiosInvalidInstruction;
ExitFlag = TRUE;
}
/***************************************************************************/
static VOID InstAAA()
{
if ( ((AL & 0x0F) > 9) || (AF==1) )
{
AL = AL + 6;
AH = AL + 1;
AF = 1;
CF = 1;
AL = AL & 0x0F;
}
}
/***************************************************************************/
static VOID InstAAD()
{
AL = (AH * 0x0A) + AL;
AH = 0;
ComputeFlags8(AL);
}
/***************************************************************************/
static VOID InstAAM()
{
AH = AL / 0x0A;
AL = AL % 0x0A;
ComputeFlags16(AX);
}
/***************************************************************************/
static VOID InstAAS()
{
if ( ((AL & 0x0F) > 9) || (AF == 1) )
{
AL = AL - 6;
AH = AH - 1;
AF = 1;
CF = 1;
AL = AL & 0x0F;
}
}
/***************************************************************************/
static VOID InstADC()
{
ULONG Left;
ULONG Right;
ULONG Result;
Left = GetOperand(LSRC,0);
Right = GetOperand(RSRC,0);
ComputeAllFlags(Left,Right,&Result,ADDOPERATION,CF);
PutOperand(LSRC,0,Result);
}
/***************************************************************************/
static VOID InstADD()
{
ULONG Left;
ULONG Right;
ULONG Result;
Left = GetOperand(LSRC,0);
Right = GetOperand(RSRC,0);
ComputeAllFlags(Left,Right,&Result,ADDOPERATION,0);
PutOperand(LSRC,0,Result);
}
/***************************************************************************/
static VOID InstAND()
{
ULONG Result;
Result = GetOperand(LSRC,0) & GetOperand(RSRC,0);
PutOperand(LSRC,0,Result);
CF = 0;
OF = 0;
ComputeSignZeroParityFlags(Result);
}
/***************************************************************************/
static VOID InstOR()
{
ULONG Result;
Result = GetOperand(LSRC,0) | GetOperand(RSRC,0);
PutOperand(LSRC,0,Result);
CF = 0;
OF = 0;
ComputeSignZeroParityFlags(Result);
}
/***************************************************************************/
static VOID InstCMP()
{
ULONG Left;
ULONG Right;
ULONG Result;
Left = GetOperand(LSRC,0);
Right = GetOperand(RSRC,0);
ComputeAllFlags(Left,Right,&Result,SUBOPERATION,0);
}
/***************************************************************************/
static VOID InstSBB()
{
ULONG Left;
ULONG Right;
ULONG Result;
Left = GetOperand(LSRC,0);
Right = GetOperand(RSRC,0);
ComputeAllFlags(Left,Right,&Result,SUBOPERATION,CF);
PutOperand(LSRC,0,Result);
}
/***************************************************************************/
static VOID InstSUB()
{
ULONG Left;
ULONG Right;
ULONG Result;
Left = GetOperand(LSRC,0);
Right = GetOperand(RSRC,0);
ComputeAllFlags(Left,Right,&Result,SUBOPERATION,0);
PutOperand(LSRC,0,Result);
}
/***************************************************************************/
static VOID InstXOR()
{
ULONG Result;
Result = GetOperand(LSRC,0) ^ GetOperand(RSRC,0);
PutOperand(LSRC,0,Result);
CF = 0;
OF = 0;
ComputeSignZeroParityFlags(Result);
}
/***************************************************************************/
static VOID InstCBW()
{
if (AL & 0x80)
AH = 0xff;
else
AH = 0x00;
}
/***************************************************************************/
static VOID InstCLC()
{
CF = 0;
}
/***************************************************************************/
static VOID InstCLD()
{
DF = 0;
}
/***************************************************************************/
static VOID InstCLI()
{
IF = 0;
}
/***************************************************************************/
static VOID InstCMC()
{
if (CF == 0)
CF = 1;
else
CF = 0;
}
/***************************************************************************/
static VOID InstCWD()
{
if (AX & 0x8000)
DX = 0xffff;
else
DX = 0x0000;
}
/***************************************************************************/
static VOID InstDAA()
{
if ( ((AL & 0x0F) > 9) || (AF==1) )
{
AL = AL + 6;
AF = 1;
}
if ( (AL > 0x9f) || (CF==1) )
{
AL = AL + 0x60;
CF = 1;
}
ComputeFlags8(AL);
}
/***************************************************************************/
static VOID InstDAS()
{
if ( ((AL & 0x0F) > 9) || (AF==1) )
{
AL = AL - 6;
AF = 1;
}
if ( (AL > 0x9f) || (CF==1) )
{
AL = AL - 0x60;
CF = 1;
}
ComputeFlags8(AL);
}
/***************************************************************************/
static VOID InstDEC()
{
ULONG Left;
Left = GetOperand(LSRC,0);
Left = Left - 1;
PutOperand(LSRC,0,Left);
if (OperationCodeByte==0xfe) // 8 Bit Operation
{
if (Left==0x7f)
OF=1;
else
OF=0;
if ((Left & 0x0f)==0x0f)
AF = 1;
else
AF = 0;
ComputeFlags8(Left);
}
else
{
if (Left==0x7fff)
OF=1;
else
OF=0;
if ((Left & 0x0f)==0x0f)
AF = 1;
else
AF = 0;
ComputeFlags16(Left);
}
}
/***************************************************************************/
static VOID InstHLT()
{
ErrorCode = x86BiosHaltInstruction;
ExitFlag = TRUE;
}
/***************************************************************************/
static VOID InstINC()
{
ULONG Left;
Left = GetOperand(LSRC,0);
Left = Left + 1;
PutOperand(LSRC,0,Left);
if (OperationCodeByte == 0xfe) // 8 bit operation
{
if (Left==0x80)
OF=1;
else
OF=0;
if ((Left & 0x0f)==0x00)
AF = 1;
else
AF = 0;
ComputeFlags8(Left);
}
else
{
if (Left==0x8000)
OF=1;
else
OF=0;
if ((Left & 0x0f)==0x00)
AF = 1;
else
AF = 0;
ComputeFlags16(Left);
}
}
/***************************************************************************/
static VOID InstLAHF()
{
AH = Flags.L & 0xd7;
}
/***************************************************************************/
static VOID InstLDS()
{
PutOperand(LSRC,0,GetOperand(RSRC,0));
DS = GetOperand(RSRC,2);
DSCacheRegister = GetSegmentCacheRegister(DS);
}
/***************************************************************************/
static VOID InstSAHF()
{
Flags.L = AH & 0xd7;
}
/***************************************************************************/
static VOID InstSTC()
{
CF = 1;
}
/***************************************************************************/
static VOID InstSTD()
{
DF = 1;
}
/***************************************************************************/
static VOID InstSTI()
{
IF = 1;
SSRegisterTouched = TRUE;
}
/***************************************************************************/
static VOID InstWAIT()
{
ErrorCode = x86BiosWaitInstruction;
ExitFlag = TRUE;
}
/***************************************************************************/
static VOID InstPUSH()
{
ULONG Value;
Value = GetOperand(LSRC,0);
SP = SP - 2;
PutStackMem(SP+0,Value);
PutStackMem(SP+1,Value >> 8);
}
/***************************************************************************/
VOID InstPUSHA()
{
USHORT OriginalSP;
OriginalSP = SP;
SP = SP - 2;
PutStackMem(SP+0,AL);
PutStackMem(SP+1,AH);
SP = SP - 2;
PutStackMem(SP+0,BL);
PutStackMem(SP+1,BH);
SP = SP - 2;
PutStackMem(SP+0,CL);
PutStackMem(SP+1,CH);
SP = SP - 2;
PutStackMem(SP+0,DL);
PutStackMem(SP+1,DH);
SP = SP - 2;
PutStackMem(SP+0,OriginalSP);
PutStackMem(SP+1,OriginalSP >> 8);
SP = SP - 2;
PutStackMem(SP+0,BP);
PutStackMem(SP+1,BP >> 8);
SP = SP - 2;
PutStackMem(SP+0,SI);
PutStackMem(SP+1,SI >> 8);
SP = SP - 2;
PutStackMem(SP+0,DI);
PutStackMem(SP+1,DI >> 8);
}
/***************************************************************************/
static VOID InstPOP()
{
ULONG Value;
Value = GetStackMem(SP+0) | (GetStackMem(SP+1) << 8);
SP = SP + 2;
PutOperand(LSRC,0,Value);
}
/***************************************************************************/
VOID InstPOPA()
{
DI = GetStackMem(SP+0) | (GetStackMem(SP+1) << 8);
SP = SP + 2;
SI = GetStackMem(SP+0) | (GetStackMem(SP+1) << 8);
SP = SP + 2;
BP = GetStackMem(SP+0) | (GetStackMem(SP+1) << 8);
SP = SP + 2;
SP = SP + 2;
DX = GetStackMem(SP+0) | (GetStackMem(SP+1) << 8);
SP = SP + 2;
CX = GetStackMem(SP+0) | (GetStackMem(SP+1) << 8);
SP = SP + 2;
BX = GetStackMem(SP+0) | (GetStackMem(SP+1) << 8);
SP = SP + 2;
AX = GetStackMem(SP+0) | (GetStackMem(SP+1) << 8);
SP = SP + 2;
}
/***************************************************************************/
static VOID InstJO()
{
if (OF==1)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJNO()
{
if (OF==0)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJB()
{
if (CF==1)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJNB()
{
if (CF==0)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJE()
{
if (ZF==1)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJNE()
{
if (ZF==0)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJBE()
{
if (CF==1 || ZF==1)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJNBE()
{
if (CF==0 && ZF==0)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJS()
{
if (SF==1)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJNS()
{
if (SF==0)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJP()
{
if (PF==1)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJNP()
{
if (PF==0)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJL()
{
if (SF!=OF)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJNL()
{
if (SF==OF)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJLE()
{
if (ZF==1 || SF!=OF)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJNLE()
{
if (ZF==0 && SF==OF)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstTEST()
{
ULONG Result;
if (OperationCodeByte == 0xf6)
GetImmediate8Operand(RSRC);
if (OperationCodeByte == 0xf7)
GetImmediate16Operand(RSRC);
Result = GetOperand(LSRC,0) & GetOperand(RSRC,0);
CF = 0;
OF = 0;
ComputeSignZeroParityFlags(Result);
}
/***************************************************************************/
static VOID InstXCHG()
{
ULONG Temp;
Temp = GetOperand(RSRC,0);
PutOperand(RSRC,0,GetOperand(LSRC,0));
PutOperand(LSRC,0,Temp);
}
/***************************************************************************/
static VOID InstMOV()
{
PutOperand(LSRC,0,GetOperand(RSRC,0));
}
/***************************************************************************/
static VOID InstLEA()
{
PutOperand(LSRC,0,RSRC->MemoryOffset.X);
}
/***************************************************************************/
static VOID InstCALL()
{
ULONG Value;
Value = GetOperand(LSRC,0);
switch (OperationCodeByte)
{
case 0xe8 : SP = SP - 2;
PutStackMem(SP+0,ip.L);
PutStackMem(SP+1,ip.H);
IP = IP + Value;
break;
case 0xff : if ( ((AddressModeByte >> 3) & 0x07) == 0x02)
{
SP = SP - 2;
PutStackMem(SP+0,ip.L);
PutStackMem(SP+1,ip.H);
IP = Value;
}
else if ( ((AddressModeByte >> 3) & 0x07) == 0x03)
{
SP = SP - 4;
PutStackMem(SP+0,ip.L);
PutStackMem(SP+1,ip.H);
PutStackMem(SP+2,cs.L);
PutStackMem(SP+3,cs.H);
IP = Value;
CS = GetOperand(LSRC,2);
CSCacheRegister = GetSegmentCacheRegister(CS);
}
break;
case 0x9a : SP = SP - 4;
PutStackMem(SP+0,ip.L);
PutStackMem(SP+1,ip.H);
PutStackMem(SP+2,cs.L);
PutStackMem(SP+3,cs.H);
IP = Value;
CS = Value >> 16;
CSCacheRegister = GetSegmentCacheRegister(CS);
break;
}
}
/***************************************************************************/
static VOID InstPUSHF()
{
SP = SP - 2;
PutStackMem(SP+0,Flags.L & 0xd7);
PutStackMem(SP+1,Flags.H & 0x0f);
}
/**********************************f*****************************************/
static VOID InstPOPF()
{
Flags.L = GetStackMem(SP+0) & 0xd7;
Flags.H = GetStackMem(SP+1) & 0x0f;
SP = SP + 2;
}
/***************************************************************************/
static VOID InstMOVS()
{
if (RepeatPrefix==TRUE)
{
while(CX!=0)
{
PutOperand(LSRC,0,GetOperand(RSRC,0));
CX = CX - 1;
SI += Delta;
DI += Delta;
LSRC->MemoryOffset.X += Delta;
RSRC->MemoryOffset.X += Delta;
}
}
else
{
PutOperand(LSRC,0,GetOperand(RSRC,0));
SI = SI + Delta;
DI = DI + Delta;
}
}
/***************************************************************************/
static VOID InstCMPS()
{
ULONG Left;
ULONG Right;
ULONG Result;
if (RepeatPrefix==TRUE)
{
while(CX!=0)
{
Left = GetOperand(LSRC,0);
Right = GetOperand(RSRC,0);
ComputeAllFlags(Left,Right,&Result,SUBOPERATION,0);
CX--;
SI += Delta;
DI += Delta;
LSRC->MemoryOffset.X += Delta;
RSRC->MemoryOffset.X += Delta;
if (ZF != RepeatZeroFlag)
return;
}
}
else
{
Left = GetOperand(LSRC,0);
Right = GetOperand(RSRC,0);
ComputeAllFlags(Left,Right,&Result,SUBOPERATION,0);
SI += Delta;
DI += Delta;
}
}
/***************************************************************************/
static VOID InstSTOS()
{
if (RepeatPrefix==TRUE)
{
while(CX!=0)
{
PutOperand(LSRC,0,GetOperand(RSRC,0));
CX--;
DI += Delta;
LSRC->MemoryOffset.X += Delta;
}
}
else
{
PutOperand(LSRC,0,GetOperand(RSRC,0));
DI += Delta;
}
}
/***************************************************************************/
static VOID InstLODS()
{
if (RepeatPrefix==TRUE)
{
while(CX!=0)
{
PutOperand(LSRC,0,GetOperand(RSRC,0));
CX--;
SI += Delta;
RSRC->MemoryOffset.X += Delta;
}
}
else
{
PutOperand(LSRC,0,GetOperand(RSRC,0));
SI += Delta;
}
}
/***************************************************************************/
static VOID InstSCAS()
{
ULONG Left;
ULONG Right;
ULONG Result;
if (RepeatPrefix==TRUE)
{
while(CX!=0)
{
Left = GetOperand(LSRC,0);
Right = GetOperand(RSRC,0);
ComputeAllFlags(Left,Right,&Result,SUBOPERATION,0);
CX--;
DI += Delta;
RSRC->MemoryOffset.X += Delta;
if (ZF != RepeatZeroFlag)
return;
}
}
else
{
Left = GetOperand(LSRC,0);
Right = GetOperand(RSRC,0);
ComputeAllFlags(Left,Right,&Result,SUBOPERATION,0);
DI += Delta;
}
}
/***************************************************************************/
static VOID InstRET()
{
ip.L = GetStackMem(SP+0);
ip.H = GetStackMem(SP+1);
SP = SP + 2;
switch(OperationCodeByte)
{
case 0xc2 : SP = SP + GetOperand(LSRC,0);
break;
case 0xca : cs.L = GetStackMem(SP + 0);
cs.H = GetStackMem(SP + 1);
CSCacheRegister = GetSegmentCacheRegister(CS);
SP = SP + 2;
SP = SP + GetOperand(LSRC,0);
break;
case 0xcb : cs.L = GetStackMem(SP + 0);
cs.H = GetStackMem(SP + 1);
CSCacheRegister = GetSegmentCacheRegister(CS);
SP = SP + 2;
break;
}
}
/***************************************************************************/
static VOID InstLES()
{
PutOperand(LSRC,0,GetOperand(RSRC,0));
ES = GetOperand(RSRC,2);
ESCacheRegister = GetSegmentCacheRegister(ES);
}
/***************************************************************************/
static VOID InstINT()
{
if (OperationCodeByte & 0x01)
GenerateINT(GetOperand(LSRC,0));
else
GenerateINT(3);
}
/***************************************************************************/
static VOID InstINTO()
{
if (OF == 1)
GenerateINT(4);
}
/***************************************************************************/
static VOID InstIRET()
{
#ifdef X86DEBUG1
AddressTrace[AddressTracePosition] = CS<<16 | IP;
AddressTracePosition = (AddressTracePosition + 1) % ADDRESSTRACESIZE;
#endif
ip.L = GetStackMem(SP+0);
ip.H = GetStackMem(SP+1);
SP = SP + 2;
cs.L = GetStackMem(SP+0);
cs.H = GetStackMem(SP+1);
CSCacheRegister = GetSegmentCacheRegister(CS);
SP = SP + 2;
Flags.L = GetStackMem(SP+0) & 0xd7;
Flags.H = GetStackMem(SP+1) & 0x0f;
SP = SP + 2;
#ifdef X86DEBUG1
AddressTrace[AddressTracePosition] = CS<<16 | IP;
AddressTracePosition = (AddressTracePosition + 1) % ADDRESSTRACESIZE;
#endif
}
/***************************************************************************/
static VOID InstROL()
{
ULONG Count;
ULONG Temp;
ULONG Value;
ULONG TempF;
Value = GetOperand(LSRC,0);
Count = GetOperand(RSRC,0);
Temp = Count;
while (Temp!=0)
{
if (OperationCodeByte & 0x01)
CF = (Value>>15) & 1;
else
CF = (Value>>7) & 1;
Value = (Value << 1) | CF;
Temp = Temp - 1;
}
if (Count==1)
{
if (OperationCodeByte & 0x01)
TempF = (Value>>15) & 1;
else
TempF = (Value>>7) & 1;
if (TempF != CF)
OF = 1;
else
OF = 0;
}
PutOperand(LSRC,0,Value);
}
/***************************************************************************/
static VOID InstROR()
{
ULONG Count;
ULONG Temp;
ULONG Value;
ULONG TempF;
Value = GetOperand(LSRC,0);
Count = GetOperand(RSRC,0);
Temp = Count;
while (Temp!=0)
{
CF = Value & 1;
if (OperationCodeByte & 0x01)
Value = ((Value >> 1) & 0x7fff) | (CF << 15);
else
Value = ((Value >> 1) & 0x7f) | (CF << 7);
Temp = Temp - 1;
}
if (Count==1)
{
if (OperationCodeByte & 0x01)
TempF = (Value>>14) & 3;
else
TempF = (Value>>6) & 3;
if (TempF==1 || TempF==2)
OF = 1;
else
OF = 0;
}
PutOperand(LSRC,0,Value);
}
/***************************************************************************/
static VOID InstRCL()
{
ULONG Count;
ULONG Temp;
ULONG Value;
ULONG TempF;
ULONG tmpcf;
Value = GetOperand(LSRC,0);
Count = GetOperand(RSRC,0);
Temp = Count;
while (Temp!=0)
{
tmpcf = CF;
if (OperationCodeByte & 0x01)
CF = (Value>>15) & 1;
else
CF = (Value>>7) & 1;
Value = (Value << 1) | tmpcf;
Temp = Temp - 1;
}
if (Count==1)
{
if (OperationCodeByte & 0x01)
TempF = (Value>>15) & 1;
else
TempF = (Value>>7) & 1;
if (TempF != CF)
OF = 1;
else
OF = 0;
}
PutOperand(LSRC,0,Value);
}
/***************************************************************************/
static VOID InstRCR()
{
ULONG Count;
ULONG Temp;
ULONG Value;
ULONG TempF;
ULONG tmpcf;
Value = GetOperand(LSRC,0);
Count = GetOperand(RSRC,0);
Temp = Count;
while (Temp!=0)
{
tmpcf = CF;
CF = Value & 1;
if (OperationCodeByte & 0x01)
Value = ((Value >> 1) & 0x7fff) | (tmpcf << 15);
else
Value = ((Value >> 1) & 0x7f) | (tmpcf << 7);
Temp = Temp - 1;
}
if (Count==1)
{
if (OperationCodeByte & 0x01)
TempF = (Value>>14) & 3;
else
TempF = (Value>>6) & 3;
if (TempF==1 || TempF==2)
OF = 1;
else
OF = 0;
}
PutOperand(LSRC,0,Value);
}
/***************************************************************************/
static VOID InstSAL()
{
ULONG Count;
ULONG Temp;
ULONG Value;
ULONG TempF;
Value = GetOperand(LSRC,0);
Count = GetOperand(RSRC,0);
Temp = Count;
while (Temp!=0)
{
if (OperationCodeByte & 0x01)
CF = (Value>>15) & 1;
else
CF = (Value>>7) & 1;
Value = (Value << 1);
Temp = Temp - 1;
}
if (Count==1)
{
if (OperationCodeByte & 0x01)
TempF = (Value>>15) & 1;
else
TempF = (Value>>7) & 1;
if (TempF != CF)
OF = 1;
else
OF = 0;
}
PutOperand(LSRC,0,Value);
ComputeSignZeroParityFlags(Value);
}
/***************************************************************************/
static VOID InstSHR()
{
ULONG Count;
ULONG Temp;
ULONG Value;
ULONG TempF;
Value = GetOperand(LSRC,0);
Count = GetOperand(RSRC,0);
Temp = Count;
while (Temp!=0)
{
CF = Value & 1;
if (OperationCodeByte & 0x01)
Value = ((Value >> 1) & 0x7fff);
else
Value = ((Value >> 1) & 0x7f);
Temp = Temp - 1;
}
if (Count==1)
{
if (OperationCodeByte & 0x01)
TempF = (Value>>14) & 3;
else
TempF = (Value>>6) & 3;
if (TempF==1 || TempF==2)
OF = 1;
else
OF = 0;
}
PutOperand(LSRC,0,Value);
ComputeSignZeroParityFlags(Value);
}
/***************************************************************************/
static VOID InstSAR()
{
ULONG Count;
ULONG Temp;
ULONG Value;
ULONG TempF;
Value = GetOperand(LSRC,0);
Count = GetOperand(RSRC,0);
Temp = Count;
while (Temp!=0)
{
CF = Value & 1;
if (OperationCodeByte & 0x01)
Value = ((Value >> 1) & 0x7fff) | (Value & 0x8000);
else
Value = ((Value >> 1) & 0x7f) | (Value & 0x80);
Temp = Temp - 1;
}
if (Count==1)
{
if (OperationCodeByte & 0x01)
TempF = (Value>>14) & 3;
else
TempF = (Value>>6) & 3;
if (TempF==1 || TempF==2)
OF = 1;
else
OF = 0;
}
PutOperand(LSRC,0,Value);
ComputeSignZeroParityFlags(Value);
}
/***************************************************************************/
static VOID InstXLAT()
{
USHORT Segment;
Segment = *pGetCurrentSegment(&DS);
AL = GetMemImmediate(Segment,BX + AL);
}
/***************************************************************************/
static VOID InstESC()
{
}
/***************************************************************************/
static VOID InstLOOPNE()
{
CX--;
if (ZF==0 && CX!=0)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstLOOPE()
{
CX--;
if (ZF==1 && CX!=0)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstLOOP()
{
CX--;
if (CX!=0)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstJCXZ()
{
if (CX==0)
IP = IP + GetOperand(LSRC,0);
}
/***************************************************************************/
static VOID InstIN()
{
ULONG Port;
ULONG Value;
Port = GetOperand(RSRC,0);
if (LSRC->OperandType == Register16Operand)
if (Port & 0x01)
{
Value = READ_REGISTER_UCHAR(BiosIsaIoBaseAddress+Port) | (READ_REGISTER_UCHAR(BiosIsaIoBaseAddress+Port+1)<<8);
}
else
{
Value = READ_REGISTER_USHORT(BiosIsaIoBaseAddress+Port);
}
else
{
Value = READ_REGISTER_UCHAR(BiosIsaIoBaseAddress+Port);
}
PutOperand(LSRC,0,Value);
}
/***************************************************************************/
static VOID InstINS()
{
ULONG Port;
ULONG Value;
Port = GetOperand(RSRC,0);
if (RepeatPrefix)
{
while(CX!=0)
{
if (OperationCodeByte & 0x01)
if (Port & 0x01)
{
Value = READ_REGISTER_UCHAR(BiosIsaIoBaseAddress+Port) | (READ_REGISTER_UCHAR(BiosIsaIoBaseAddress+Port+1)<<8);
}
else
{
Value = READ_REGISTER_USHORT(BiosIsaIoBaseAddress+Port);
}
else
{
Value = READ_REGISTER_UCHAR(BiosIsaIoBaseAddress+Port);
}
PutOperand(LSRC,0,Value);
CX--;
DI += Delta;
LSRC->MemoryOffset.X += Delta;
}
}
else
{
if (OperationCodeByte & 0x01)
if (Port & 0x01)
{
Value = READ_REGISTER_UCHAR(BiosIsaIoBaseAddress+Port) | (READ_REGISTER_UCHAR(BiosIsaIoBaseAddress+Port+1)<<8);
}
else
{
Value = READ_REGISTER_USHORT(BiosIsaIoBaseAddress+Port);
}
else
{
Value = READ_REGISTER_UCHAR(BiosIsaIoBaseAddress+Port);
}
PutOperand(LSRC,0,Value);
DI += Delta;
}
}
/***************************************************************************/
static VOID InstOUT()
{
ULONG Port;
ULONG Value;
Port = GetOperand(RSRC,0);
Value = GetOperand(LSRC,0);
if (LSRC->OperandType == Register16Operand)
if (Port & 0x01)
{
WRITE_REGISTER_UCHAR(BiosIsaIoBaseAddress + Port,Value);
WRITE_REGISTER_UCHAR(BiosIsaIoBaseAddress + Port + 1,Value>>8);
}
else
{
WRITE_REGISTER_USHORT(BiosIsaIoBaseAddress + Port,Value);
}
else
{
WRITE_REGISTER_UCHAR(BiosIsaIoBaseAddress + Port,Value);
}
}
/***************************************************************************/
static VOID InstOUTS()
{
ULONG Port;
ULONG Value;
Port = GetOperand(RSRC,0);
if (RepeatPrefix)
{
while(CX!=0)
{
Value = GetOperand(LSRC,0);
if (OperationCodeByte & 0x01)
if (Port & 0x01)
{
WRITE_REGISTER_UCHAR(BiosIsaIoBaseAddress + Port,Value);
WRITE_REGISTER_UCHAR(BiosIsaIoBaseAddress + Port + 1,Value>>8);
}
else
{
WRITE_REGISTER_USHORT(BiosIsaIoBaseAddress + Port,Value);
}
else
{
WRITE_REGISTER_UCHAR(BiosIsaIoBaseAddress + Port,Value);
}
CX--;
SI += Delta;
LSRC->MemoryOffset.X += Delta;
}
}
else
{
Value = GetOperand(LSRC,0);
if (OperationCodeByte & 0x01)
if (Port & 0x01)
{
WRITE_REGISTER_UCHAR(BiosIsaIoBaseAddress + Port,Value);
WRITE_REGISTER_UCHAR(BiosIsaIoBaseAddress + Port + 1,Value>>8);
}
else
{
WRITE_REGISTER_USHORT(BiosIsaIoBaseAddress + Port,Value);
}
else
{
WRITE_REGISTER_UCHAR(BiosIsaIoBaseAddress + Port,Value);
}
SI += Delta;
}
}
/***************************************************************************/
static VOID InstJMP()
{
ULONG Value;
Value = GetOperand(LSRC,0);
switch(OperationCodeByte)
{
case 0xe9 : IP = IP + Value;
break;
case 0xea : IP = Value;
CS = Value >> 16;
CSCacheRegister = GetSegmentCacheRegister(CS);
break;
case 0xeb : IP = IP + Value;
break;
case 0xff : if (reg==4)
IP = Value;
if (reg==5)
{
IP = Value;
CS = GetOperand(LSRC,2);
CSCacheRegister = GetSegmentCacheRegister(CS);
}
break;
}
}
/***************************************************************************/
static VOID InstLOCK()
{
LockPrefix = TRUE;
}
/***************************************************************************/
static VOID InstREP()
{
RepeatPrefix = TRUE;
RepeatZeroFlag = OperationCodeByte & 0x01;
}
/***************************************************************************/
static VOID InstNOT()
{
PutOperand(LSRC,0,0xFFFF - GetOperand(LSRC,0));
}
/***************************************************************************/
static VOID InstNEG()
{
ULONG Left;
ULONG Result;
Left = GetOperand(LSRC,0);
Result = 0xFFFF - Left + 1;
PutOperand(LSRC,0,Result);
if (Result == 0)
CF = 0;
else
CF = 1;
}
/***************************************************************************/
static VOID InstMUL()
{
ULONG Temp;
if (OperationCodeByte & 0x01)
{
Temp = (ULONG)(AX) * (ULONG)(GetOperand(LSRC,0));
AX = Temp & 0xffff;
DX = (Temp >> 16) & 0xffff;
if (DX==0)
CF = 0;
else
CF = 1;
}
else
{
Temp = (ULONG)(AL) * (ULONG)(GetOperand(LSRC,0));
AX = Temp & 0xffff;
if (AH==0)
CF = 0;
else
CF = 1;
}
OF = CF;
}
/***************************************************************************/
static VOID InstIMUL()
{
LONG Temp;
if (OperationCodeByte & 0x01)
{
if (OperationCodeByte == 0xf7)
Temp = (ULONG)(AX) * (ULONG)(GetOperand(LSRC,0));
else
Temp = (ULONG)(GetOperand(LSRC,0)) * (ULONG)(GetOperand(RSRC,0));
AX = Temp & 0xffff;
DX = (Temp >> 16) & 0xffff;
if ( ((AX & 0x8000)==0 && DX==0) || ((AX & 0x8000)==0x8000 && DX==0xffff))
CF = 0;
else
CF = 1;
}
else
{
if (OperationCodeByte == 0xf6)
Temp = (ULONG)(AL) * (ULONG)(GetOperand(LSRC,0));
else
Temp = (ULONG)(GetOperand(LSRC,0)) * (ULONG)(GetOperand(RSRC,0));
AX = Temp & 0xffff;
if ( ((AL & 0x80)==0 && AH==0) || ((AL & 0x80)==0x80 && AH==0xff))
CF = 0;
else
CF = 1;
}
OF = CF;
}
/***************************************************************************/
static VOID InstDIV()
{
ULONG Numr;
ULONG Divr;
if (OperationCodeByte & 0x01)
{
Numr = ((ULONG)DX << 16) | AX;
Divr = (ULONG)GetOperand(LSRC,0);
if (Divr==0)
{
ErrorCode = x86BiosDivideByZero;
ExitFlag = TRUE;
return;
}
if ((Numr/Divr) > 0xffff)
{
ErrorCode = x86BiosDivideByZero;
ExitFlag = TRUE;
return;
}
AX = Numr/Divr;
DX = Numr%Divr;
}
else
{
Numr = AX;
Divr = (ULONG)GetOperand(LSRC,0);
if (Divr==0)
{
ErrorCode = x86BiosDivideByZero;
ExitFlag = TRUE;
return;
}
if ((Numr/Divr) > 0xff)
{
ErrorCode = x86BiosDivideByZero;
ExitFlag = TRUE;
return;
}
AL = Numr/Divr;
AH = Numr%Divr;
}
}
/***************************************************************************/
static VOID InstIDIV()
{
ULONG Numr;
ULONG Divr;
if (OperationCodeByte & 0x01)
{
Numr = ((ULONG)DX << 16) | AX;
Divr = (ULONG)GetOperand(LSRC,0);
if (Divr==0)
{
ErrorCode = x86BiosDivideByZero;
ExitFlag = TRUE;
return;
}
if ((Numr/Divr) > 0xffff)
{
ErrorCode = x86BiosDivideByZero;
ExitFlag = TRUE;
return;
}
AX = Numr/Divr;
DX = Numr%Divr;
}
else
{
Numr = AX;
Divr = (ULONG)GetOperand(LSRC,0);
if (Divr==0)
{
ErrorCode = x86BiosDivideByZero;
ExitFlag = TRUE;
return;
}
if ((Numr/Divr) > 0xff)
{
ErrorCode = x86BiosDivideByZero;
ExitFlag = TRUE;
return;
}
AL = Numr/Divr;
AH = Numr%Divr;
}
}
/***************************************************************************/
static VOID InstSegmentOveride()
{
SegmentOveridePrefix = TRUE;
OverideSegmentRegister = LSRC->Register16;
}
/***************************************************************************/
//
// Most of the 80286 Protected Mode Instructions are sent to this function.
// Most of these instructions are unimplemented because they are not
// normally used, and hence are difficult to test. So far, I have not seen
// any addin card BIOS's use these instructions.
//
static VOID InstDescriptorTable()
{
if (ExtendedOperationCodeByte==0x00)
{
switch(reg)
{
case 0 : DISPLAY("SLDT");
break;
case 1 : DISPLAY("STR");
break;
case 2 : DISPLAY("LLDT");
break;
case 3 : DISPLAY("LTR");
break;
case 4 : DISPLAY("VERR read");
break;
case 5 : DISPLAY("VERR write");
break;
default : DISPLAY("Unknown Instruction");
break;
}
}
else if (ExtendedOperationCodeByte==0x01)
{
switch(reg)
{
case 0 : PutOperand(LSRC,0,gdtLimit);
PutOperand(LSRC,2,(gdtBase & 0x00ffffff));
PutOperand(LSRC,4,((gdtBase & 0x00ffffff) | 0xff000000)>>16);
return;
case 1 : DISPLAY("SIDT");
PutOperand(LSRC,0,idtLimit);
PutOperand(LSRC,2,(idtBase & 0x00ffffff));
PutOperand(LSRC,4,((idtBase & 0x00ffffff) | 0xff000000)>>16);
break;
case 2 : gdtLimit = GetOperand(LSRC,0);
gdtBase = (GetOperand(LSRC,2) | (GetOperand(LSRC,4)<<16)) & 0x00ffffff;
return;
case 3 : idtLimit = GetOperand(LSRC,0);
idtBase = (GetOperand(LSRC,2) | (GetOperand(LSRC,4)<<16)) & 0x00ffffff;
return;
case 4 : PutOperand(LSRC,0,msw);
return;
case 6 : msw = GetOperand(LSRC,0);
return;
default : DISPLAY("Unknown Instruction");
break;
}
}
else if (ExtendedOperationCodeByte==0x02)
{
DISPLAY("LAR");
}
else if (ExtendedOperationCodeByte==0x03)
{
DISPLAY("LSL");
}
else if (ExtendedOperationCodeByte==0x06)
{
DISPLAY("CTS");
}
else if (ExtendedOperationCodeByte==0x63)
{
DISPLAY("ARPL");
}
else
{
DISPLAY("Unknown Instruction");
}
DISPLAY("\n\r");
InstInvalid();
}
/***************************************************************************/
VOID InstENTER()
{
ULONG Left;
ULONG Right;
Left = GetOperand(LSRC,0);
Right = GetOperand(RSRC,0);
if (Right==0)
{
SP = SP - 2;
PutStackMem(SP+0,BP);
PutStackMem(SP+1,BP>>8);
BP = SP;
SP = SP - Left;
}
else
{
DISPLAY("ENTER with L!=0\n\r");
ErrorCode = x86BiosInvalidInstruction;
ExitFlag = TRUE;
}
}
/***************************************************************************/
VOID InstLEAVE()
{
SP = BP;
BP = GetStackMem(SP+0) | (GetStackMem(SP+1)<<8);
SP = SP + 2;
}
/***************************************************************************/
/*++
Address Decoding Tables:
The size of the address decoding table was reduced by defining 8 bit
tokens for the different address decoding functions. These tokens
are stored in the address decoding table. When an instruction is
being decoded, a token will be retrieved for the left operand and for
the right operand. The DecodeOperandFunctionTable[] is used to
convert this 8 bit token to a function pointer which can be called.
The AddressModeByteRequired[] table is used to identify which address
modes require and address mode byte to be parsed from an instruction.
If either the left operand or the right operand use an address mode
for which AddressModeByteRequired[] is true, then the second byte of
the instruction is an address mode byte.
--*/
#define NULL_OPERAND 0
#define REG8_MEM8 1 // AddressModeByte required
#define REG16_MEM16 2 // AddressModeByte required
#define REG8 3 // AddressModeByte required
#define REG16 4 // AddressModeByte required
#define SEGREG 5 // AddressModeByte required
#define EMBEDDED_REG8 6
#define EMBEDDED_REG16 7
#define ACC8 8
#define ACC16 9
#define IMMED8 10
#define IMMED8_SX 11
#define IMMED16 12
#define SHORT_LABEL 13
#define IMMED32 14
#define MEM8 15
#define MEM16 16
#define CONST_1 17
#define REG_CL 18
#define REG_DX 19
#define STRING8_DSSI 20
#define STRING16_DSSI 21
#define STRING8_ESDI 22
#define STRING16_ESDI 23
#define REG_ES 24
#define REG_DS 25
#define REG_SS 26
#define REG_CS 27
static const UCHAR AddressModeByteRequired[28] = {0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
static const VOID (*DecodeOperandFunctionTable[28])() =
{
NullFunction,
GetMemory8OrRegister8Operand,
GetMemory16OrRegister16Operand,
GetRegister8Operand,
GetRegister16Operand,
GetSegmentRegisterOperand,
GetEmbeddedRegister8Operand,
GetEmbeddedRegister16Operand,
GetAccumulator8Operand,
GetAccumulator16Operand,
GetImmediate8Operand,
GetImmediateSignExtend8Operand,
GetImmediate16Operand,
GetShortLabelOperand,
GetImmediate32Operand,
GetMemory8Operand,
GetMemory16Operand,
GetConstantOneOperand,
GetRegisterCLOperand,
GetRegisterDXOperand,
GetString8DSSIOperand,
GetString16DSSIOperand,
GetString8ESDIOperand,
GetString16ESDIOperand,
GetRegisterESOperand,
GetRegisterDSOperand,
GetRegisterSSOperand,
GetRegisterCSOperand
};
static const UCHAR DecodeOperandsTable[256][2] =
{
{ REG8_MEM8 , REG8 }, // 00 ADD
{ REG16_MEM16 , REG16 }, // 01 ADD
{ REG8 , REG8_MEM8 }, // 02 ADD
{ REG16 , REG16_MEM16 }, // 03 ADD
{ ACC8 , IMMED8 }, // 04 ADD
{ ACC16 , IMMED16 }, // 05 ADD
{ REG_ES , NULL_OPERAND }, // 06 PUSH ES
{ REG_ES , NULL_OPERAND }, // 07 POP ES
{ REG8_MEM8 , REG8 }, // 08 OR
{ REG16_MEM16 , REG16 }, // 09 OR
{ REG8 , REG8_MEM8 }, // 0A OR
{ REG16 , REG16_MEM16 }, // 0B OR
{ ACC8 , IMMED8 }, // 0C OR
{ ACC16 , IMMED16 }, // 0D OR
{ REG_CS , NULL_OPERAND }, // 0E PUSH CS
{ NULL_OPERAND , NULL_OPERAND }, // 0F 286 Extended Operation Codes
{ REG8_MEM8 , REG8 }, // 10 ADC
{ REG16_MEM16 , REG16 }, // 11 ADC
{ REG8 , REG8_MEM8 }, // 12 ADC
{ REG16 , REG16_MEM16 }, // 13 ADC
{ ACC8 , IMMED8 }, // 14 ADC
{ ACC16 , IMMED16 }, // 15 ADC
{ REG_SS , NULL_OPERAND }, // 16 PUSH SS
{ REG_SS , NULL_OPERAND }, // 17 POP SS
{ REG8_MEM8 , REG8 }, // 18 SBB
{ REG16_MEM16 , REG16 }, // 19 SBB
{ REG8 , REG8_MEM8 }, // 1A SBB
{ REG16 , REG16_MEM16 }, // 1B SBB
{ ACC8 , IMMED8 }, // 1C SBB
{ ACC16 , IMMED16 }, // 1D SBB
{ REG_DS , NULL_OPERAND }, // 1E PUSH DS
{ REG_DS , NULL_OPERAND }, // 1F POP DS
{ REG8_MEM8 , REG8 }, // 20 AND
{ REG16_MEM16 , REG16 }, // 21 AND
{ REG8 , REG8_MEM8 }, // 22 ANC
{ REG16 , REG16_MEM16 }, // 23 AND
{ ACC8 , IMMED8 }, // 24 AND
{ ACC16 , IMMED16 }, // 25 AND
{ REG_ES , NULL_OPERAND }, // 26 ES: (segment overide)
{ NULL_OPERAND , NULL_OPERAND }, // 27 DAA
{ REG8_MEM8 , REG8 }, // 28 SUB
{ REG16_MEM16 , REG16 }, // 29 SUB
{ REG8 , REG8_MEM8 }, // 2A SUB
{ REG16 , REG16_MEM16 }, // 2B SUB
{ ACC8 , IMMED8 }, // 2C SUB
{ ACC16 , IMMED16 }, // 2D SUB
{ REG_CS , NULL_OPERAND }, // 2E CS: (segment overide)
{ NULL_OPERAND , NULL_OPERAND }, // 2F DAS
{ REG8_MEM8 , REG8 }, // 30 XOR
{ REG16_MEM16 , REG16 }, // 31 XOR
{ REG8 , REG8_MEM8 }, // 32 XOR
{ REG16 , REG16_MEM16 }, // 33 XOR
{ ACC8 , IMMED8 }, // 34 XOR
{ ACC16 , IMMED16 }, // 35 XOR
{ REG_SS , NULL_OPERAND }, // 36 SS: (segment overide)
{ NULL_OPERAND , NULL_OPERAND }, // 37 AAA
{ REG8_MEM8 , REG8 }, // 38 CMP
{ REG16_MEM16 , REG16 }, // 39 CMP
{ REG8 , REG8_MEM8 }, // 3A CMP
{ REG16 , REG16_MEM16 }, // 3B CMP
{ ACC8 , IMMED8 }, // 3C CMP
{ ACC16 , IMMED16 }, // 3D CMP
{ REG_DS , NULL_OPERAND }, // 3E DS: (segment overide)
{ NULL_OPERAND , NULL_OPERAND }, // 3F AAS
{ EMBEDDED_REG16 , NULL_OPERAND }, // 40 INC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 41 INC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 42 INC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 43 INC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 44 INC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 45 INC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 46 INC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 47 INC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 48 DEC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 49 DEC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 4A DEC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 4B DEC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 4C DEC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 4D DEC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 4E DEC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 4F DEC
{ EMBEDDED_REG16 , NULL_OPERAND }, // 50 PUSH
{ EMBEDDED_REG16 , NULL_OPERAND }, // 51 PUSH
{ EMBEDDED_REG16 , NULL_OPERAND }, // 52 PUSH
{ EMBEDDED_REG16 , NULL_OPERAND }, // 53 PUSH
{ EMBEDDED_REG16 , NULL_OPERAND }, // 54 PUSH
{ EMBEDDED_REG16 , NULL_OPERAND }, // 55 PUSH
{ EMBEDDED_REG16 , NULL_OPERAND }, // 56 PUSH
{ EMBEDDED_REG16 , NULL_OPERAND }, // 57 PUSH
{ EMBEDDED_REG16 , NULL_OPERAND }, // 58 POP
{ EMBEDDED_REG16 , NULL_OPERAND }, // 59 POP
{ EMBEDDED_REG16 , NULL_OPERAND }, // 5A POP
{ EMBEDDED_REG16 , NULL_OPERAND }, // 5B POP
{ EMBEDDED_REG16 , NULL_OPERAND }, // 5C POP
{ EMBEDDED_REG16 , NULL_OPERAND }, // 5D POP
{ EMBEDDED_REG16 , NULL_OPERAND }, // 5E POP
{ EMBEDDED_REG16 , NULL_OPERAND }, // 5F POP
{ NULL_OPERAND , NULL_OPERAND }, // 60 PUSHA
{ NULL_OPERAND , NULL_OPERAND }, // 61 POPA
{ NULL_OPERAND , NULL_OPERAND }, // 62 (not used)
{ NULL_OPERAND , NULL_OPERAND }, // 63 (not used)
{ NULL_OPERAND , NULL_OPERAND }, // 64 (not used)
{ NULL_OPERAND , NULL_OPERAND }, // 65 (not used)
{ NULL_OPERAND , NULL_OPERAND }, // 66 (not used)
{ NULL_OPERAND , NULL_OPERAND }, // 67 (not used)
{ IMMED16 , NULL_OPERAND }, // 68 PUSH
{ REG16_MEM16 , IMMED16 }, // 69 IMUL
{ IMMED8_SX , NULL_OPERAND }, // 6A PUSH
{ REG16_MEM16 , IMMED8_SX }, // 6B IMUL
{ STRING8_ESDI , REG_DX }, // 6C INS
{ STRING16_ESDI , REG_DX }, // 6D INS
{ STRING8_DSSI , REG_DX }, // 6E OUTS
{ STRING16_DSSI , REG_DX }, // 6F OUTS
{ SHORT_LABEL , NULL_OPERAND }, // 70 JO
{ SHORT_LABEL , NULL_OPERAND }, // 71 JNO
{ SHORT_LABEL , NULL_OPERAND }, // 72 JB
{ SHORT_LABEL , NULL_OPERAND }, // 73 JNB
{ SHORT_LABEL , NULL_OPERAND }, // 74 JE
{ SHORT_LABEL , NULL_OPERAND }, // 75 JNE
{ SHORT_LABEL , NULL_OPERAND }, // 76 JBE
{ SHORT_LABEL , NULL_OPERAND }, // 77 JNBE
{ SHORT_LABEL , NULL_OPERAND }, // 78 JS
{ SHORT_LABEL , NULL_OPERAND }, // 79 JNS
{ SHORT_LABEL , NULL_OPERAND }, // 7A JP
{ SHORT_LABEL , NULL_OPERAND }, // 7B JNP
{ SHORT_LABEL , NULL_OPERAND }, // 7C JL
{ SHORT_LABEL , NULL_OPERAND }, // 7D JNL
{ SHORT_LABEL , NULL_OPERAND }, // 7E JLE
{ SHORT_LABEL , NULL_OPERAND }, // 7F JNLE
{ REG8_MEM8 , IMMED8 }, // 80 ADD/OR/ADC/SBB/AND/SUB/XOR/CMP
{ REG16_MEM16 , IMMED16 }, // 81 ADD/OR/ADC/SBB/AND/SUB/XOR/CMP
{ REG8_MEM8 , IMMED8 }, // 82 ADD/OR/ADC/SBB/AND/SUB/XOR/CMP
{ REG16_MEM16 , IMMED8_SX }, // 83 ADD/OR/ADC/SBB/AND/SUB/XOR/CMP
{ REG8_MEM8 , REG8 }, // 84 TEST
{ REG16_MEM16 , REG16 }, // 85 TEST
{ REG8_MEM8 , REG8 }, // 86 XCHG
{ REG16_MEM16 , REG16 }, // 87 XCHG
{ REG8_MEM8 , REG8 }, // 88 MOV
{ REG16_MEM16 , REG16 }, // 89 MOV
{ REG8 , REG8_MEM8 }, // 8A MOV
{ REG16 , REG16_MEM16 }, // 8B MOV
{ REG16_MEM16 , SEGREG }, // 8C MOV
{ REG16 , REG16_MEM16 }, // 8D LEA
{ SEGREG , REG16_MEM16 }, // 8E MOV
{ REG16_MEM16 , NULL_OPERAND }, // 8F POP
{ ACC16 , EMBEDDED_REG16 }, // 90 XCHG
{ ACC16 , EMBEDDED_REG16 }, // 91 XCHG
{ ACC16 , EMBEDDED_REG16 }, // 92 XCHG
{ ACC16 , EMBEDDED_REG16 }, // 93 XCHG
{ ACC16 , EMBEDDED_REG16 }, // 94 XCHG
{ ACC16 , EMBEDDED_REG16 }, // 95 XCHG
{ ACC16 , EMBEDDED_REG16 }, // 96 XCHG
{ ACC16 , EMBEDDED_REG16 }, // 97 XCHG
{ NULL_OPERAND , NULL_OPERAND }, // 98 CBW
{ NULL_OPERAND , NULL_OPERAND }, // 99 CWD
{ IMMED32 , NULL_OPERAND }, // 9A CALL
{ NULL_OPERAND , NULL_OPERAND }, // 9B WAIT
{ NULL_OPERAND , NULL_OPERAND }, // 9C PUSHF
{ NULL_OPERAND , NULL_OPERAND }, // 9D POPF
{ NULL_OPERAND , NULL_OPERAND }, // 9E SAHF
{ NULL_OPERAND , NULL_OPERAND }, // 9F LAHF
{ ACC8 , MEM8 }, // A0 MOV
{ ACC16 , MEM16 }, // A1 MOV
{ MEM8 , ACC8 }, // A2 MOV
{ MEM16 , ACC16 }, // A3 MOV
{ STRING8_ESDI , STRING8_DSSI }, // A4 MOVS
{ STRING16_ESDI , STRING16_DSSI }, // A5 MOVS
{ STRING8_ESDI , STRING8_DSSI }, // A6 CMPS
{ STRING16_ESDI , STRING16_DSSI }, // A7 CMPS
{ ACC8 , IMMED8 }, // A8 TEST
{ ACC16 , IMMED16 }, // A9 TEST
{ STRING8_ESDI , ACC8 }, // AA STOS
{ STRING16_ESDI , ACC16 }, // AB STOS
{ ACC8 , STRING8_DSSI }, // AC LODS
{ ACC16 , STRING16_DSSI }, // AD LODS
{ ACC8 , STRING8_ESDI }, // AE SCAS
{ ACC16 , STRING16_ESDI }, // AF SCAS
{ EMBEDDED_REG8 , IMMED8 }, // B0 MOV
{ EMBEDDED_REG8 , IMMED8 }, // B1 MOV
{ EMBEDDED_REG8 , IMMED8 }, // B2 MOV
{ EMBEDDED_REG8 , IMMED8 }, // B3 MOV
{ EMBEDDED_REG8 , IMMED8 }, // B4 MOV
{ EMBEDDED_REG8 , IMMED8 }, // B5 MOV
{ EMBEDDED_REG8 , IMMED8 }, // B6 MOV
{ EMBEDDED_REG8 , IMMED8 }, // B7 MOV
{ EMBEDDED_REG16 , IMMED16 }, // B8 MOV
{ EMBEDDED_REG16 , IMMED16 }, // B9 MOV
{ EMBEDDED_REG16 , IMMED16 }, // BA MOV
{ EMBEDDED_REG16 , IMMED16 }, // BB MOV
{ EMBEDDED_REG16 , IMMED16 }, // BC MOV
{ EMBEDDED_REG16 , IMMED16 }, // BD MOV
{ EMBEDDED_REG16 , IMMED16 }, // BE MOV
{ EMBEDDED_REG16 , IMMED16 }, // BF MOV
{ REG8_MEM8 , IMMED8 }, // C0 (286) ROL/ROR/RCL/RCR/SAL/SHR/SAR
{ REG16_MEM16 , IMMED8 }, // C1 (286) ROL/ROR/RCL/RCR/SAL/SHR/SAR
{ IMMED16 , NULL_OPERAND }, // C2 RET
{ NULL_OPERAND , NULL_OPERAND }, // C3 RET
{ REG16 , REG16_MEM16 }, // C4 LES
{ REG16 , REG16_MEM16 }, // C5 LDS
{ REG8_MEM8 , IMMED8 }, // C6 MOV
{ REG16_MEM16 , IMMED16 }, // C7 MOV
{ IMMED16 , IMMED8 }, // C8 ENTER
{ NULL_OPERAND , NULL_OPERAND }, // C9 LEAVE
{ IMMED16 , NULL_OPERAND }, // CA RET
{ NULL_OPERAND , NULL_OPERAND }, // CB RET
{ NULL_OPERAND , NULL_OPERAND }, // CC INT 3
{ IMMED8 , NULL_OPERAND }, // CD INT
{ NULL_OPERAND , NULL_OPERAND }, // CE INTO
{ NULL_OPERAND , NULL_OPERAND }, // CF IRET
{ REG8_MEM8 , CONST_1 }, // D0 ROL/ROR/RCL/RCR/SAL/SHR/SAR
{ REG16_MEM16 , CONST_1 }, // D1 ROL/ROR/RCL/RCR/SAL/SHR/SAR
{ REG8_MEM8 , REG_CL }, // D2 ROL/ROR/RCL/RCR/SAL/SHR/SAR
{ REG16_MEM16 , REG_CL }, // D3 ROL/ROR/RCL/RCR/SAL/SHR/SAR
{ IMMED8 , NULL_OPERAND }, // D4 AAM
{ IMMED8 , NULL_OPERAND }, // D5 AAD
{ NULL_OPERAND , NULL_OPERAND }, // D6 (not used)
{ NULL_OPERAND , NULL_OPERAND }, // D7 XLAT
{ IMMED8 , NULL_OPERAND }, // D8 ESC
{ REG16_MEM16 , NULL_OPERAND }, // D9 ESC
{ REG16_MEM16 , NULL_OPERAND }, // DA ESC
{ REG16_MEM16 , NULL_OPERAND }, // DB ESC
{ REG16_MEM16 , NULL_OPERAND }, // DC ESC
{ REG16_MEM16 , NULL_OPERAND }, // DD ESC
{ REG16_MEM16 , NULL_OPERAND }, // DE ESC
{ IMMED8 , NULL_OPERAND }, // DF ESC
{ SHORT_LABEL , NULL_OPERAND }, // E0 LOOPNE
{ SHORT_LABEL , NULL_OPERAND }, // E1 LOOPE
{ SHORT_LABEL , NULL_OPERAND }, // E2 LOOP
{ SHORT_LABEL , NULL_OPERAND }, // E3 JCXZ
{ ACC8 , IMMED8 }, // E4 IN
{ ACC16 , IMMED8 }, // E5 IN
{ ACC8 , IMMED8 }, // E6 OUT
{ ACC16 , IMMED8 }, // E7 OUT
{ IMMED16 , NULL_OPERAND }, // E8 CALL
{ IMMED16 , NULL_OPERAND }, // E9 JMP
{ IMMED32 , NULL_OPERAND }, // EA JMP
{ SHORT_LABEL , NULL_OPERAND }, // EB JMP
{ ACC8 , REG_DX }, // EC IN
{ ACC16 , REG_DX }, // ED IN
{ ACC8 , REG_DX }, // EE OUT
{ ACC16 , REG_DX }, // EF OUT
{ NULL_OPERAND , NULL_OPERAND }, // F0 LOCK
{ NULL_OPERAND , NULL_OPERAND }, // F1 (not used)
{ NULL_OPERAND , NULL_OPERAND }, // F2 REPNE
{ NULL_OPERAND , NULL_OPERAND }, // F3 REPE
{ NULL_OPERAND , NULL_OPERAND }, // F4 HLT
{ NULL_OPERAND , NULL_OPERAND }, // F5 CMC
{ REG8_MEM8 , NULL_OPERAND }, // F6 TEST/NOT/NEG/MUL/IMUL/DIV/IDIV/TEST
{ REG16_MEM16 , NULL_OPERAND }, // F7 TEST/NOT/NEG/MUL/IMUL/DIV/IDIV/TEST
{ NULL_OPERAND , NULL_OPERAND }, // F8 CLC
{ NULL_OPERAND , NULL_OPERAND }, // F9 STC
{ NULL_OPERAND , NULL_OPERAND }, // FA CLI
{ NULL_OPERAND , NULL_OPERAND }, // FB STI
{ NULL_OPERAND , NULL_OPERAND }, // FC CLD
{ NULL_OPERAND , NULL_OPERAND }, // FD STD
{ REG8_MEM8 , NULL_OPERAND }, // FE INC/DEC
{ REG16_MEM16 , NULL_OPERAND } // FF INC/DEC/CALL/JMP/PUSH
};
/*++
Instruction Decoding Tables:
The size of the instruction decoding table was reduced by defining 8 bit
tokens for the different instruction functions. These tokens are stored
in the instruction decoding table. When an instruction is being decoded,
a token will be retrieved. For instructions without address mode bytes,
the first token for that instruction will be retrieved. For instructions
with address mode byes, bits 3-5 of the address mode byte will be used
as a sub index into the instruction decoding table. This table has 256
rows for each possible operation code value, and is 8 columns wide for
each of the 8 possible values for bits 3-5 of the address mode byte.
Once an instruction token has been retrieved, the
DecodeInstructionFunctionTable[] can be used to convert the token to a
function pointer. This function is called to execute the instruction.
--*/
#define NUMINSTRUCTIONTYPES 105
#define INST_INV 0
#define INST_ADD 1
#define INST_PUSH 2
#define INST_POP 3
#define INST_OR 4
#define INST_ADC 5
#define INST_SBB 6
#define INST_AND 7
#define INST_ES_ 8
#define INST_DAA 9
#define INST_SUB 10
#define INST_CS_ 11
#define INST_DAS 12
#define INST_XOR 13
#define INST_SS_ 14
#define INST_AAA 15
#define INST_CMP 16
#define INST_DS_ 17
#define INST_AAS 18
#define INST_INC 19
#define INST_DEC 20
#define INST_JO 21
#define INST_JNO 22
#define INST_JB 23
#define INST_JNB 24
#define INST_JE 25
#define INST_JNE 26
#define INST_JBE 27
#define INST_JNBE 28
#define INST_JS 29
#define INST_JNS 30
#define INST_JP 31
#define INST_JNP 32
#define INST_JL 33
#define INST_JNL 34
#define INST_JLE 35
#define INST_JNLE 36
#define INST_TEST 37
#define INST_XCHG 38
#define INST_MOV 39
#define INST_LEA 40
#define INST_CBW 41
#define INST_CWD 42
#define INST_CALL 43
#define INST_WAIT 44
#define INST_PUSHF 45
#define INST_POPF 46
#define INST_SAHF 47
#define INST_LAHF 48
#define INST_MOVS 49
#define INST_CMPS 50
#define INST_STOS 51
#define INST_LODS 52
#define INST_SCAS 53
#define INST_RET 54
#define INST_LES 55
#define INST_LDS 56
#define INST_INT 57
#define INST_INTO 58
#define INST_IRET 59
#define INST_ROL 60
#define INST_ROR 61
#define INST_RCL 62
#define INST_RCR 63
#define INST_SAL 64
#define INST_SHR 65
#define INST_SAR 66
#define INST_AAM 67
#define INST_AAD 68
#define INST_XLAT 69
#define INST_ESC 70
#define INST_LOOPNE 71
#define INST_LOOPE 72
#define INST_LOOP 73
#define INST_JCXZ 74
#define INST_IN 75
#define INST_OUT 76
#define INST_LOCK 77
#define INST_REP 78
#define INST_HLT 79
#define INST_CMC 80
#define INST_NOT 81
#define INST_NEG 82
#define INST_MUL 83
#define INST_IMUL 84
#define INST_DIV 85
#define INST_IDIV 86
#define INST_CLC 87
#define INST_STC 88
#define INST_CLI 89
#define INST_STI 90
#define INST_CLD 91
#define INST_STD 92
#define INST_JMP 93
#define INST_SEG 94
#define INST_PUSHA 95
#define INST_POPA 96
#define INST_DT 97
#define INST_OUTS 98
#define INST_ENTER 99
#define INST_LEAVE 100
#define INST_INS 101
#ifdef X86DEBUG
static const UCHAR *InstructionNames[NUMINSTRUCTIONTYPES] =
{
"Invalid ",
"ADD ",
"PUSH ",
"POP ",
"OR ",
"ADC ",
"SBB ",
"AND ",
"ES: ",
"DAA ",
"SUB ",
"CS: ",
"DAS ",
"XOR ",
"SS: ",
"AAA ",
"CMP ",
"DS: ",
"AAS ",
"INC ",
"DEC ",
"JO ",
"JNO ",
"JB ",
"JNB ",
"JE ",
"JNE ",
"JBE ",
"JNBE ",
"JS ",
"JNS ",
"JP ",
"JNP ",
"JL ",
"JNL ",
"JLE ",
"JNLE ",
"TEST ",
"XCHG ",
"MOV ",
"LEA ",
"CBW ",
"CWD ",
"CALL ",
"WAIT ",
"PUSHF ",
"POPF ",
"SAHF ",
"LAHF ",
"MOVS ",
"CMPS ",
"STOS ",
"LODS ",
"SCAS ",
"RET ",
"LES ",
"LDS ",
"INT ",
"INTO ",
"IRET ",
"ROL ",
"ROR ",
"RCL ",
"RCR ",
"SAL ",
"SHR ",
"SAR ",
"AAM ",
"AAD ",
"XLAT ",
"ESC ",
"LOOPNE ",
"LOOPE ",
"LOOP ",
"JCXZ ",
"IN ",
"OUT ",
"LOCK ",
"REP ",
"HLT ",
"CMC ",
"NOT ",
"NEG ",
"MUL ",
"IMUL ",
"DIV ",
"IDIV ",
"CLC ",
"STC ",
"CLI ",
"STI ",
"CLD ",
"STD ",
"JMP ",
" ",
"PUSHA ",
"POPA ",
"286DT ",
"OUTS ",
"ENTER ",
"LEAVE ",
"INS ",
};
#endif
static const VOID (*DecodeInstructionFunctionTable[NUMINSTRUCTIONTYPES])() =
{
InstInvalid,
InstADD,
InstPUSH,
InstPOP,
InstOR,
InstADC,
InstSBB,
InstAND,
NULL,
InstDAA,
InstSUB,
NULL,
InstDAS,
InstXOR,
NULL,
InstAAA,
InstCMP,
NULL,
InstAAS,
InstINC,
InstDEC,
InstJO,
InstJNO,
InstJB,
InstJNB,
InstJE,
InstJNE,
InstJBE,
InstJNBE,
InstJS,
InstJNS,
InstJP,
InstJNP,
InstJL,
InstJNL,
InstJLE,
InstJNLE,
InstTEST,
InstXCHG,
InstMOV,
InstLEA,
InstCBW,
InstCWD,
InstCALL,
InstWAIT,
InstPUSHF,
InstPOPF,
InstSAHF,
InstLAHF,
InstMOVS,
InstCMPS,
InstSTOS,
InstLODS,
InstSCAS,
InstRET,
InstLES,
InstLDS,
InstINT,
InstINTO,
InstIRET,
InstROL,
InstROR,
InstRCL,
InstRCR,
InstSAL,
InstSHR,
InstSAR,
InstAAM,
InstAAD,
InstXLAT,
InstESC,
InstLOOPNE,
InstLOOPE,
InstLOOP,
InstJCXZ,
InstIN,
InstOUT,
InstLOCK,
InstREP,
InstHLT,
InstCMC,
InstNOT,
InstNEG,
InstMUL,
InstIMUL,
InstDIV,
InstIDIV,
InstCLC,
InstSTC,
InstCLI,
InstSTI,
InstCLD,
InstSTD,
InstJMP,
InstSegmentOveride,
InstPUSHA,
InstPOPA,
InstDescriptorTable,
InstOUTS,
InstENTER,
InstLEAVE,
InstINS,
};
static const UCHAR DecodeInstructionTable[256][8] =
{
{ INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD } , // 00
{ INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD } , // 01
{ INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD } , // 02
{ INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD } , // 03
{ INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD } , // 04
{ INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD , INST_ADD } , // 05
{ INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH} , // 06
{ INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP } , // 07
{ INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR } , // 08
{ INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR } , // 09
{ INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR } , // 0A
{ INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR } , // 0B
{ INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR } , // 0C
{ INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR , INST_OR } , // 0D
{ INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH} , // 0E
{ INST_DT , INST_DT , INST_DT , INST_DT , INST_DT , INST_DT , INST_DT , INST_DT } , // 0F
{ INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC } , // 10
{ INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC } , // 11
{ INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC } , // 12
{ INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC } , // 13
{ INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC } , // 14
{ INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC , INST_ADC } , // 15
{ INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH} , // 16
{ INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP } , // 17
{ INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB } , // 18
{ INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB } , // 19
{ INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB } , // 1A
{ INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB } , // 1B
{ INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB } , // 1C
{ INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB , INST_SBB } , // 1D
{ INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH} , // 1E
{ INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP } , // 1F
{ INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND } , // 20
{ INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND } , // 21
{ INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND } , // 22
{ INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND } , // 23
{ INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND } , // 24
{ INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND , INST_AND } , // 25
{ INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG } , // 26
{ INST_DAA , INST_DAA , INST_DAA , INST_DAA , INST_DAA , INST_DAA , INST_DAA , INST_DAA } , // 27
{ INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB } , // 28
{ INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB } , // 29
{ INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB } , // 2A
{ INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB } , // 2B
{ INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB } , // 2C
{ INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB , INST_SUB } , // 2D
{ INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG } , // 2E
{ INST_DAS , INST_DAS , INST_DAS , INST_DAS , INST_DAS , INST_DAS , INST_DAS , INST_DAS } , // 2F
{ INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR } , // 30
{ INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR } , // 31
{ INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR } , // 32
{ INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR } , // 33
{ INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR } , // 34
{ INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR , INST_XOR } , // 35
{ INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG } , // 36
{ INST_AAA , INST_AAA , INST_AAA , INST_AAA , INST_AAA , INST_AAA , INST_AAA , INST_AAA } , // 37
{ INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP } , // 38
{ INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP } , // 39
{ INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP } , // 3A
{ INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP } , // 3B
{ INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP } , // 3C
{ INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP , INST_CMP } , // 3D
{ INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG , INST_SEG } , // 3E
{ INST_AAS , INST_AAS , INST_AAS , INST_AAS , INST_AAS , INST_AAS , INST_AAS , INST_AAS } , // 3F
{ INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC } , // 40
{ INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC } , // 41
{ INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC } , // 42
{ INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC } , // 43
{ INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC } , // 44
{ INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC } , // 45
{ INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC } , // 46
{ INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC , INST_INC } , // 47
{ INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC } , // 48
{ INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC } , // 49
{ INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC } , // 4A
{ INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC } , // 4B
{ INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC } , // 4C
{ INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC } , // 4D
{ INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC } , // 4E
{ INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC , INST_DEC } , // 4F
{ INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH} , // 50
{ INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH} , // 51
{ INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH} , // 52
{ INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH} , // 53
{ INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH} , // 54
{ INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH} , // 55
{ INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH} , // 56
{ INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH} , // 57
{ INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP } , // 58
{ INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP } , // 59
{ INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP } , // 5A
{ INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP } , // 5B
{ INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP } , // 5C
{ INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP } , // 5D
{ INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP } , // 5E
{ INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP , INST_POP } , // 5F
{ INST_PUSHA , INST_PUSHA , INST_PUSHA , INST_PUSHA , INST_PUSHA , INST_PUSHA , INST_PUSHA , INST_PUSHA} , // 60
{ INST_POPA , INST_POPA , INST_POPA , INST_POPA , INST_POPA , INST_POPA , INST_POPA , INST_POPA} , // 61
{ INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV } , // 62
{ INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV } , // 63
{ INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV } , // 64
{ INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV } , // 65
{ INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV } , // 66
{ INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV } , // 67
{ INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH} , // 68
{ INST_IMUL , INST_IMUL , INST_IMUL , INST_IMUL , INST_IMUL , INST_IMUL , INST_IMUL , INST_IMUL} , // 69
{ INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH , INST_PUSH} , // 6A
{ INST_IMUL , INST_IMUL , INST_IMUL , INST_IMUL , INST_IMUL , INST_IMUL , INST_IMUL , INST_IMUL} , // 6B
{ INST_INS , INST_INS , INST_INS , INST_INS , INST_INS , INST_INS , INST_INS , INST_INS } , // 6C
{ INST_INS , INST_INS , INST_INS , INST_INS , INST_INS , INST_INS , INST_INS , INST_INS } , // 6D
{ INST_OUTS , INST_OUTS , INST_OUTS , INST_OUTS , INST_OUTS , INST_OUTS , INST_OUTS , INST_OUTS} , // 6E
{ INST_OUTS , INST_OUTS , INST_OUTS , INST_OUTS , INST_OUTS , INST_OUTS , INST_OUTS , INST_OUTS} , // 6F
{ INST_JO , INST_JO , INST_JO , INST_JO , INST_JO , INST_JO , INST_JO , INST_JO } , // 70
{ INST_JNO , INST_JNO , INST_JNO , INST_JNO , INST_JNO , INST_JNO , INST_JNO , INST_JNO } , // 71
{ INST_JB , INST_JB , INST_JB , INST_JB , INST_JB , INST_JB , INST_JB , INST_JB } , // 72
{ INST_JNB , INST_JNB , INST_JNB , INST_JNB , INST_JNB , INST_JNB , INST_JNB , INST_JNB } , // 73
{ INST_JE , INST_JE , INST_JE , INST_JE , INST_JE , INST_JE , INST_JE , INST_JE } , // 74
{ INST_JNE , INST_JNE , INST_JNE , INST_JNE , INST_JNE , INST_JNE , INST_JNE , INST_JNE } , // 75
{ INST_JBE , INST_JBE , INST_JBE , INST_JBE , INST_JBE , INST_JBE , INST_JBE , INST_JBE } , // 76
{ INST_JNBE , INST_JNBE , INST_JNBE , INST_JNBE , INST_JNBE , INST_JNBE , INST_JNBE , INST_JNBE} , // 77
{ INST_JS , INST_JS , INST_JS , INST_JS , INST_JS , INST_JS , INST_JS , INST_JS } , // 78
{ INST_JNS , INST_JNS , INST_JNS , INST_JNS , INST_JNS , INST_JNS , INST_JNS , INST_JNS } , // 79
{ INST_JP , INST_JP , INST_JP , INST_JP , INST_JP , INST_JP , INST_JP , INST_JP } , // 7A
{ INST_JNP , INST_JNP , INST_JNP , INST_JNP , INST_JNP , INST_JNP , INST_JNP , INST_JNP } , // 7B
{ INST_JL , INST_JL , INST_JL , INST_JL , INST_JL , INST_JL , INST_JL , INST_JL } , // 7C
{ INST_JNL , INST_JNL , INST_JNL , INST_JNL , INST_JNL , INST_JNL , INST_JNL , INST_JNL } , // 7D
{ INST_JLE , INST_JLE , INST_JLE , INST_JLE , INST_JLE , INST_JLE , INST_JLE , INST_JLE } , // 7E
{ INST_JNLE , INST_JNLE , INST_JNLE , INST_JNLE , INST_JNLE , INST_JNLE , INST_JNLE , INST_JNLE} , // 7F
{ INST_ADD , INST_OR , INST_ADC , INST_SBB , INST_AND , INST_SUB , INST_XOR , INST_CMP } , // 80
{ INST_ADD , INST_OR , INST_ADC , INST_SBB , INST_AND , INST_SUB , INST_XOR , INST_CMP } , // 81
{ INST_ADD , INST_OR , INST_ADC , INST_SBB , INST_AND , INST_SUB , INST_XOR , INST_CMP } , // 82
{ INST_ADD , INST_OR , INST_ADC , INST_SBB , INST_AND , INST_SUB , INST_XOR , INST_CMP } , // 83
{ INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST} , // 84
{ INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST} , // 85
{ INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG} , // 86
{ INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG} , // 87
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // 88
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // 89
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // 8A
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // 8B
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_INV , INST_INV , INST_INV , INST_INV } , // 8C
{ INST_LEA , INST_LEA , INST_LEA , INST_LEA , INST_LEA , INST_LEA , INST_LEA , INST_LEA } , // 8D
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_INV , INST_INV , INST_INV , INST_INV } , // 8E
{ INST_POP , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV } , // 8F
{ INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG} , // 90
{ INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG} , // 91
{ INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG} , // 92
{ INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG} , // 93
{ INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG} , // 94
{ INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG} , // 95
{ INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG} , // 96
{ INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG , INST_XCHG} , // 97
{ INST_CBW , INST_CBW , INST_CBW , INST_CBW , INST_CBW , INST_CBW , INST_CBW , INST_CBW } , // 98
{ INST_CWD , INST_CWD , INST_CWD , INST_CWD , INST_CWD , INST_CWD , INST_CWD , INST_CWD } , // 99
{ INST_CALL , INST_CALL , INST_CALL , INST_CALL , INST_CALL , INST_CALL , INST_CALL , INST_CALL} , // 9A
{ INST_WAIT , INST_WAIT , INST_WAIT , INST_WAIT , INST_WAIT , INST_WAIT , INST_WAIT , INST_WAIT} , // 9B
{ INST_PUSHF , INST_PUSHF , INST_PUSHF , INST_PUSHF , INST_PUSHF , INST_PUSHF , INST_PUSHF , INST_PUSHF} , // 9C
{ INST_POPF , INST_POPF , INST_POPF , INST_POPF , INST_POPF , INST_POPF , INST_POPF , INST_POPF} , // 9D
{ INST_SAHF , INST_SAHF , INST_SAHF , INST_SAHF , INST_SAHF , INST_SAHF , INST_SAHF , INST_SAHF} , // 9E
{ INST_LAHF , INST_LAHF , INST_LAHF , INST_LAHF , INST_LAHF , INST_LAHF , INST_LAHF , INST_LAHF} , // 9F
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // A0
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // A1
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // A2
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // A3
{ INST_MOVS , INST_MOVS , INST_MOVS , INST_MOVS , INST_MOVS , INST_MOVS , INST_MOVS , INST_MOVS} , // A4
{ INST_MOVS , INST_MOVS , INST_MOVS , INST_MOVS , INST_MOVS , INST_MOVS , INST_MOVS , INST_MOVS} , // A5
{ INST_CMPS , INST_CMPS , INST_CMPS , INST_CMPS , INST_CMPS , INST_CMPS , INST_CMPS , INST_CMPS} , // A6
{ INST_CMPS , INST_CMPS , INST_CMPS , INST_CMPS , INST_CMPS , INST_CMPS , INST_CMPS , INST_CMPS} , // A7
{ INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST} , // A8
{ INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST , INST_TEST} , // A9
{ INST_STOS , INST_STOS , INST_STOS , INST_STOS , INST_STOS , INST_STOS , INST_STOS , INST_STOS} , // AA
{ INST_STOS , INST_STOS , INST_STOS , INST_STOS , INST_STOS , INST_STOS , INST_STOS , INST_STOS} , // AB
{ INST_LODS , INST_LODS , INST_LODS , INST_LODS , INST_LODS , INST_LODS , INST_LODS , INST_LODS} , // AC
{ INST_LODS , INST_LODS , INST_LODS , INST_LODS , INST_LODS , INST_LODS , INST_LODS , INST_LODS} , // AD
{ INST_SCAS , INST_SCAS , INST_SCAS , INST_SCAS , INST_SCAS , INST_SCAS , INST_SCAS , INST_SCAS} , // AE
{ INST_SCAS , INST_SCAS , INST_SCAS , INST_SCAS , INST_SCAS , INST_SCAS , INST_SCAS , INST_SCAS} , // AF
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // B0
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // B1
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // B2
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // B3
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // B4
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // B5
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // B6
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // B7
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // B8
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // B9
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // BA
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // BB
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // BC
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // BD
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // BE
{ INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV , INST_MOV } , // BF
{ INST_ROL , INST_ROR , INST_RCL , INST_RCR , INST_SAL , INST_SHR , INST_INV , INST_SAR } , // C0
{ INST_ROL , INST_ROR , INST_RCL , INST_RCR , INST_SAL , INST_SHR , INST_INV , INST_SAR } , // C1
{ INST_RET , INST_RET , INST_RET , INST_RET , INST_RET , INST_RET , INST_RET , INST_RET } , // C2
{ INST_RET , INST_RET , INST_RET , INST_RET , INST_RET , INST_RET , INST_RET , INST_RET } , // C3
{ INST_LES , INST_LES , INST_LES , INST_LES , INST_LES , INST_LES , INST_LES , INST_LES } , // C4
{ INST_LDS , INST_LDS , INST_LDS , INST_LDS , INST_LDS , INST_LDS , INST_LDS , INST_LDS } , // C5
{ INST_MOV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV } , // C6
{ INST_MOV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV } , // C7
{ INST_ENTER , INST_ENTER , INST_ENTER , INST_ENTER , INST_ENTER , INST_ENTER , INST_ENTER , INST_ENTER} , // C8
{ INST_LEAVE , INST_LEAVE , INST_LEAVE , INST_LEAVE , INST_LEAVE , INST_LEAVE , INST_LEAVE , INST_LEAVE} , // C9
{ INST_RET , INST_RET , INST_RET , INST_RET , INST_RET , INST_RET , INST_RET , INST_RET } , // CA
{ INST_RET , INST_RET , INST_RET , INST_RET , INST_RET , INST_RET , INST_RET , INST_RET } , // CB
{ INST_INT , INST_INT , INST_INT , INST_INT , INST_INT , INST_INT , INST_INT , INST_INT } , // CC
{ INST_INT , INST_INT , INST_INT , INST_INT , INST_INT , INST_INT , INST_INT , INST_INT } , // CD
{ INST_INTO , INST_INTO , INST_INTO , INST_INTO , INST_INTO , INST_INTO , INST_INTO , INST_INTO} , // CE
{ INST_IRET , INST_IRET , INST_IRET , INST_IRET , INST_IRET , INST_IRET , INST_IRET , INST_IRET} , // CF
{ INST_ROL , INST_ROR , INST_RCL , INST_RCR , INST_SAL , INST_SHR , INST_INV , INST_SAR } , // D0
{ INST_ROL , INST_ROR , INST_RCL , INST_RCR , INST_SAL , INST_SHR , INST_INV , INST_SAR } , // D1
{ INST_ROL , INST_ROR , INST_RCL , INST_RCR , INST_SAL , INST_SHR , INST_INV , INST_SAR } , // D2
{ INST_ROL , INST_ROR , INST_RCL , INST_RCR , INST_SAL , INST_SHR , INST_INV , INST_SAR } , // D3
{ INST_AAM , INST_AAM , INST_AAM , INST_AAM , INST_AAM , INST_AAM , INST_AAM , INST_AAM } , // D4
{ INST_AAD , INST_AAD , INST_AAD , INST_AAD , INST_AAD , INST_AAD , INST_AAD , INST_AAD } , // D5
{ INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV } , // D6
{ INST_XLAT , INST_XLAT , INST_XLAT , INST_XLAT , INST_XLAT , INST_XLAT , INST_XLAT , INST_XLAT} , // D7
{ INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC } , // D8
{ INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC } , // D9
{ INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC } , // DA
{ INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC } , // DB
{ INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC } , // DC
{ INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC } , // DD
{ INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC } , // DE
{ INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC , INST_ESC } , // DF
{ INST_LOOPNE, INST_LOOPNE, INST_LOOPNE, INST_LOOPNE, INST_LOOPNE, INST_LOOPNE, INST_LOOPNE, INST_LOOPNE} , // E0
{ INST_LOOPE , INST_LOOPE , INST_LOOPE , INST_LOOPE , INST_LOOPE , INST_LOOPE , INST_LOOPE , INST_LOOPE} , // E1
{ INST_LOOP , INST_LOOP , INST_LOOP , INST_LOOP , INST_LOOP , INST_LOOP , INST_LOOP , INST_LOOP} , // E2
{ INST_JCXZ , INST_JCXZ , INST_JCXZ , INST_JCXZ , INST_JCXZ , INST_JCXZ , INST_JCXZ , INST_JCXZ} , // E3
{ INST_IN , INST_IN , INST_IN , INST_IN , INST_IN , INST_IN , INST_IN , INST_IN } , // E4
{ INST_IN , INST_IN , INST_IN , INST_IN , INST_IN , INST_IN , INST_IN , INST_IN } , // E5
{ INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT } , // E6
{ INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT } , // E7
{ INST_CALL , INST_CALL , INST_CALL , INST_CALL , INST_CALL , INST_CALL , INST_CALL , INST_CALL} , // E8
{ INST_JMP , INST_JMP , INST_JMP , INST_JMP , INST_JMP , INST_JMP , INST_JMP , INST_JMP } , // E9
{ INST_JMP , INST_JMP , INST_JMP , INST_JMP , INST_JMP , INST_JMP , INST_JMP , INST_JMP } , // EA
{ INST_JMP , INST_JMP , INST_JMP , INST_JMP , INST_JMP , INST_JMP , INST_JMP , INST_JMP } , // EB
{ INST_IN , INST_IN , INST_IN , INST_IN , INST_IN , INST_IN , INST_IN , INST_IN } , // EC
{ INST_IN , INST_IN , INST_IN , INST_IN , INST_IN , INST_IN , INST_IN , INST_IN } , // ED
{ INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT } , // EE
{ INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT , INST_OUT } , // EF
{ INST_LOCK , INST_LOCK , INST_LOCK , INST_LOCK , INST_LOCK , INST_LOCK , INST_LOCK , INST_LOCK} , // F0
{ INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV } , // F1
{ INST_REP , INST_REP , INST_REP , INST_REP , INST_REP , INST_REP , INST_REP , INST_REP } , // F2
{ INST_REP , INST_REP , INST_REP , INST_REP , INST_REP , INST_REP , INST_REP , INST_REP } , // F3
{ INST_HLT , INST_HLT , INST_HLT , INST_HLT , INST_HLT , INST_HLT , INST_HLT , INST_HLT } , // F4
{ INST_CMC , INST_CMC , INST_CMC , INST_CMC , INST_CMC , INST_CMC , INST_CMC , INST_CMC } , // F5
{ INST_TEST , INST_INV , INST_NOT , INST_NEG , INST_MUL , INST_IMUL , INST_DIV , INST_IDIV} , // F6
{ INST_TEST , INST_INV , INST_NOT , INST_NEG , INST_MUL , INST_IMUL , INST_DIV , INST_IDIV} , // F7
{ INST_CLC , INST_CLC , INST_CLC , INST_CLC , INST_CLC , INST_CLC , INST_CLC , INST_CLC } , // F8
{ INST_STC , INST_STC , INST_STC , INST_STC , INST_STC , INST_STC , INST_STC , INST_STC } , // F9
{ INST_CLI , INST_CLI , INST_CLI , INST_CLI , INST_CLI , INST_CLI , INST_CLI , INST_CLI } , // FA
{ INST_STI , INST_STI , INST_STI , INST_STI , INST_STI , INST_STI , INST_STI , INST_STI } , // FB
{ INST_CLD , INST_CLD , INST_CLD , INST_CLD , INST_CLD , INST_CLD , INST_CLD , INST_CLD } , // FC
{ INST_STD , INST_STD , INST_STD , INST_STD , INST_STD , INST_STD , INST_STD , INST_STD } , // FD
{ INST_INC , INST_DEC , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV , INST_INV } , // FE
{ INST_INC , INST_DEC , INST_CALL , INST_CALL , INST_JMP , INST_JMP , INST_PUSH , INST_INV } , // FF
};
//
// Debugging functions
//
#ifdef X86DEBUG1
static VOID DisplayProcessorState()
{
UCHAR S[512];
PrintProcessorState(S);
DISPLAY(S);
}
static VOID DisplayCurrentInstruction()
{
UCHAR S[256];
ULONG i;
ULONG Column;
//
// Print Instruction Address
//
sprintf(S,"%04X:%04X ",CS,CurrentIP.X);
DISPLAY(S);
for(i=0;i<7;i++)
if ((CurrentIP.X + i) < IP)
{
sprintf(S,"%02X",CodeMem(CurrentIP.X+i));
DISPLAY(S);
}
else
DISPLAY(" ");
//
// Print Instruction Opcode
//
if (OperationCodeByte==0x26)
{
sprintf(S,"ES: ");
DISPLAY(S);
}
else if (OperationCodeByte==0x2E)
{
sprintf(S,"CS: ");
DISPLAY(S);
}
else if (OperationCodeByte==0x36)
{
sprintf(S,"SS: ");
DISPLAY(S);
}
else if (OperationCodeByte==0x3E)
{
sprintf(S,"DS: ");
DISPLAY(S);
}
else
{
sprintf(S,"%s",InstructionNames[DecodeInstructionTable[OperationCodeByte][InstructionSubIndex]]);
DISPLAY(S);
//
// Print Instruction Operands
//
Column = 0;
if (OperationCodeByte == 0xe8 ||
OperationCodeByte == 0xe9 ||
OperationCodeByte == 0xeb ||
(OperationCodeByte >= 0x70 && OperationCodeByte <= 0x7F))
{
sprintf(S,"%04X",IP+GetOperand(LSRC,0));
DISPLAY(S);
Column = Column + strlen(S);
}
else
{
if (LSRC->OperandType != NullOperand)
{
PrintOperandName(LSRC,S);
DISPLAY(S);
Column = Column + strlen(S);
}
if (RSRC->OperandType != NullOperand)
{
DISPLAY(",");
PrintOperandName(RSRC,S);
DISPLAY(S);
Column = Column + strlen(S) + 1;
}
}
for(i=Column;i<35;i++)
DISPLAY(" ");
//
// Print Memory Operand Value
//
if (LSRC->OperandType == Memory8Operand || LSRC->OperandType==Memory16Operand)
{
PrintMemorySegmentName(LSRC,S);
DISPLAY(S);
sprintf(S,":%04X",LSRC->MemoryOffset.X);
DISPLAY(S);
DISPLAY("=");
PrintOperandValue(LSRC,S);
DISPLAY(S);
}
if (RSRC->OperandType == Memory8Operand || RSRC->OperandType==Memory16Operand)
{
PrintMemorySegmentName(RSRC,S);
DISPLAY(S);
sprintf(S,":%04X",RSRC->MemoryOffset.X);
DISPLAY(S);
DISPLAY("=");
PrintOperandValue(RSRC,S);
DISPLAY(S);
}
}
DISPLAY("\n\r");
}
/***************************************************************************/
static VOID DecodeInstruction()
{
LSRC->OperandType = NullOperand;
RSRC->OperandType = NullOperand;
CurrentIP.X = IP;
OperationCodeByte = CodeMem(IP); IP++;
if (OperationCodeByte == 0x0f)
{
ExtendedOperationCodeByte = CodeMem(IP); IP++;
if (ExtendedOperationCodeByte == 0x01)
GetMemory16OrRegister16Operand(LSRC);
}
else
{
if (AddressModeByteRequired[DecodeOperandsTable[OperationCodeByte][0]] ||
AddressModeByteRequired[DecodeOperandsTable[OperationCodeByte][1]] )
{
GetAddressModeByte();
InstructionSubIndex = reg;
}
else
InstructionSubIndex = 0;
(DecodeOperandFunctionTable[DecodeOperandsTable[OperationCodeByte][0]])(LSRC);
(DecodeOperandFunctionTable[DecodeOperandsTable[OperationCodeByte][1]])(RSRC);
}
}
/***************************************************************************/
static VOID ExecuteInstruction()
{
ULONG SavedSegmentOveridePrefix;
ULONG SavedRepeatPrefix;
ULONG SavedLockPrefix;
if (SegmentOveridePrefix==TRUE ||
RepeatPrefix==TRUE ||
LockPrefix==TRUE )
{
SavedSegmentOveridePrefix = SegmentOveridePrefix;
SavedRepeatPrefix = RepeatPrefix;
SavedLockPrefix = LockPrefix;
(DecodeInstructionFunctionTable[DecodeInstructionTable[OperationCodeByte][InstructionSubIndex]])();
if (SavedSegmentOveridePrefix==SegmentOveridePrefix &&
SavedRepeatPrefix==RepeatPrefix &&
SavedLockPrefix==LockPrefix )
{
SegmentOveridePrefix = FALSE;
RepeatPrefix = FALSE;
LockPrefix = FALSE;
}
}
else
{
(DecodeInstructionFunctionTable[DecodeInstructionTable[OperationCodeByte][InstructionSubIndex]])();
}
}
/***************************************************************************/
static VOID CommandMode()
{
UCHAR ch;
UCHAR Command[256];
ULONG Done = FALSE;
REGISTER32 SavedCurrentIP;
USHORT SavedIP;
USHORT SavedCS;
USHORT i;
USHORT j;
UCHAR Value;
ULONG DefaultSegment;
ULONG DefaultParameter;
USHORT DataSegment;
USHORT DataAddress;
USHORT Parameter;
UCHAR CommandType;
SavedCurrentIP = CurrentIP;
SavedIP = IP;
SavedCS = CS;
DisplayProcessorState();
DecodeInstruction();
DisplayCurrentInstruction();
CurrentIP = SavedCurrentIP;
IP = SavedIP;
do
{
DISPLAY("-");
i=0;
do
{
GETCHAR(ch);
PUTCHAR(ch);
if (ch==0x08 && i>0)
i--;
else if (ch>=32 && ch<=127)
{
Command[i++] = ch;
}
}
while(ch!=0x0d);
Command[i] = 0;
DISPLAY("\n\r");
DefaultSegment = TRUE;
DataSegment = 0;
i=0;
for(;(Command[i]==' ' || Command[i]==':') && Command[i]!=0;i++);
for(j=i;Command[i]!=' ' && Command[i]!=':' && Command[i]!=0;i++);
CommandType = Command[j];
for(;(Command[i]==' ' || Command[i]==':') && Command[i]!=0;i++);
for(j=i;Command[i]!=' ' && Command[i]!=':' && Command[i]!=0;i++);
if (Command[i]==':')
{
DefaultSegment = FALSE;
Command[i]=0;
i++;
if (strcmp(&(Command[j]),"ds")==0 || strcmp(&(Command[j]),"DS")==0)
DataSegment = DS;
else if (strcmp(&(Command[j]),"es")==0 || strcmp(&(Command[j]),"ES")==0)
DataSegment = ES;
else if (strcmp(&(Command[j]),"ss")==0 || strcmp(&(Command[j]),"SS")==0)
DataSegment = SS;
else if (strcmp(&(Command[j]),"cs")==0 || strcmp(&(Command[j]),"CS")==0)
DataSegment = SavedCS;
else
DataSegment = atoh(&(Command[j]));
for(;(Command[i]==' ' || Command[i]==':') && Command[i]!=0;i++);
for(;Command[i]==' ' && Command[i]==':' && Command[i]!=0;i++);
for(j=i;(Command[i]!=' ' || Command[i]!=':') && Command[i]!=0;i++);
}
if (Command[j]==0)
{
DefaultParameter = TRUE;
Parameter = 0;
}
else
{
DefaultParameter = FALSE;
Parameter = atoh(&(Command[j]));
}
switch(CommandType)
{
case 'a' :
case 'A' : DISPLAY("Address Trace\n\r");
for(i=0;i<ADDRESSTRACESIZE;i+=2)
{
PRINT3(" Jump FAR from %04X:%04X to ",AddressTrace[AddressTracePosition]>>16,AddressTrace[AddressTracePosition]&0xffff);
DISPLAY(PrintMessage);
AddressTracePosition = (AddressTracePosition + 1) % ADDRESSTRACESIZE;
PRINT3("%04X:%04X\n\r",AddressTrace[AddressTracePosition]>>16,AddressTrace[AddressTracePosition]&0xffff);
DISPLAY(PrintMessage);
AddressTracePosition = (AddressTracePosition + 1) % ADDRESSTRACESIZE;
}
DISPLAY("\n\r");
break;
case 'g' :
case 'G' : GoFlag = TRUE;
if (!DefaultSegment)
StopSegment = DataSegment;
if (!DefaultParameter)
StopOffset = Parameter;
Done = TRUE;
break;
case 'u' :
case 'U' : if (!DefaultSegment)
{
CS = DataSegment;
CSCacheRegister = GetSegmentCacheRegister(CS);
}
if (!DefaultParameter)
IP = Parameter;
for(i=0;i<20;i++)
{
DecodeInstruction();
DisplayCurrentInstruction();
}
break;
case 't' :
case 'T' : if (!DefaultSegment)
SavedCS = DataSegment;
if (!DefaultParameter)
SavedIP = Parameter;
Done = TRUE;
GoFlag = FALSE;
break;
case 'd' :
case 'D' : if (DefaultSegment)
DataSegment = DS;
if (!DefaultParameter)
DataAddress = Parameter;
for(i=0;i<8;i++)
{
PRINT3("%04X:%04X ",DataSegment,DataAddress+i*16);
DISPLAY(PrintMessage);
for(j=0;j<16;j++)
{
Value = GetMemImmediate(DataSegment,DataAddress+i*16+j);
PRINT2("%02X ",Value);
DISPLAY(PrintMessage);
}
DISPLAY(" ");
for(j=0;j<16;j++)
{
Value = GetMemImmediate(DataSegment,DataAddress+i*16+j);
if (Value<32 || Value >=128)
Value = '.';
PRINT2("%c",Value);
DISPLAY(PrintMessage);
}
DISPLAY("\n\r");
}
break;
case 'r' :
case 'R' : CurrentIP = SavedCurrentIP;
IP = SavedIP;
CS = SavedCS;
DisplayProcessorState();
DecodeInstruction();
DisplayCurrentInstruction();
CurrentIP = SavedCurrentIP;
IP = SavedIP;
CS = SavedCS;
break;
case 'm' :
case 'M' : msw = 0;
Flags.X = 0;
break;
case 'i' :
case 'I' : if (!DefaultParameter)
{
PRINT3("in %04X = %02X\n\r",Parameter,inp(Parameter));
DISPLAY(PrintMessage);
}
break;
case 'o' :
case 'O' : if (!DefaultSegment && !DefaultParameter)
{
outp(DataSegment,Parameter);
PRINT3("out %04X,%02X\n\r",DataSegment,Parameter);
DISPLAY(PrintMessage);
}
break;
}
}
while (Done == FALSE);
CurrentIP = SavedCurrentIP;
IP = SavedIP;
CS = SavedCS;
CSCacheRegister = GetSegmentCacheRegister(CS);
}
#endif
static VOID Interpreter()
/*++
Routine Description:
This function is the main loop for the emulator. It decodes operands
and executes the instructions until the exit condition is met, or an
error occurs.
Arguments:
None.
Return Value:
None.
--*/
{
ULONG SavedSegmentOveridePrefix; // Saved state of the SegmentOveridePrefix variable.
ULONG SavedRepeatPrefix; // Saved state of the RepeatPrefix variable.
ULONG SavedLockPrefix; // Saved state of the LockPrefix variable.
ULONG TrapFlagSet;
ExitFlag = FALSE;
//
// Loop until the exit condition is met.
//
while(ExitFlag==FALSE)
{
#ifdef X86DEBUG1
//
// See if there is input on the debug serial port
//
if (inp(0x3f8+5) & 0x0001)
GoFlag = FALSE;
#endif
#ifdef X86DEBUG1
//
// See if a break point has been reached.
//
if (CS==StopSegment && IP==StopOffset)
GoFlag = FALSE;
if (GoFlag == FALSE)
CommandMode();
#endif
//
// See if the exit condition has been met.
//
if (CS==ExitSegment && IP==ExitOffset)
{
ExitFlag = TRUE;
return;
}
//
// Check the condition of the trap flag. Execute the current instruction
// and then check to see if the trap flag was set before the instruction
// was executed.
//
if (TF)
TrapFlagSet = TRUE;
else
TrapFlagSet = FALSE;
//
// Initialize source operand variables and save the instruction pointer.
//
LSRC->OperandType = NullOperand;
RSRC->OperandType = NullOperand;
CurrentIP.X = IP;
//
// Read the operation code byte from memory
//
OperationCodeByte = CodeMem(IP); IP++;
//
// Decode the left and right operands
//
if (OperationCodeByte == 0x0f)
{
//
// This is a 286 Protected Mode Instructions
//
ExtendedOperationCodeByte = CodeMem(IP); IP++;
if (ExtendedOperationCodeByte == 0x01)
GetMemory16OrRegister16Operand(LSRC);
}
else
{
//
// See if an address mode byte needs to be parsed and compute the sub index
// into the instruction decoding table.
//
if (AddressModeByteRequired[DecodeOperandsTable[OperationCodeByte][0]] ||
AddressModeByteRequired[DecodeOperandsTable[OperationCodeByte][1]] )
{
GetAddressModeByte();
InstructionSubIndex = reg;
}
else
InstructionSubIndex = 0;
//
// Call address decoding function for the left operand
//
(DecodeOperandFunctionTable[DecodeOperandsTable[OperationCodeByte][0]])(LSRC);
//
// Call address decoding function for the right operand
//
(DecodeOperandFunctionTable[DecodeOperandsTable[OperationCodeByte][1]])(RSRC);
}
//
// Execute the instruction
//
if (SegmentOveridePrefix==TRUE ||
RepeatPrefix==TRUE ||
LockPrefix==TRUE )
{
//
// Prefix instructions have been parsed, so handle this in a special case.
// Save the state of the prefix variables.
//
SavedSegmentOveridePrefix = SegmentOveridePrefix;
SavedRepeatPrefix = RepeatPrefix;
SavedLockPrefix = LockPrefix;
//
// Call function to execute the instruction
//
(DecodeInstructionFunctionTable[DecodeInstructionTable[OperationCodeByte][InstructionSubIndex]])();
//
// See if this was another prefix instruction by comparing the state of the
// prefix variables before and after the current instruction has been executed.
//
if (SavedSegmentOveridePrefix==SegmentOveridePrefix &&
SavedRepeatPrefix==RepeatPrefix &&
SavedLockPrefix==LockPrefix )
{
//
// If the state did not change, then the current instruction is not a prefix
// instruction, so all the prefix variables should be cleared.
//
SegmentOveridePrefix = FALSE;
RepeatPrefix = FALSE;
LockPrefix = FALSE;
}
}
else
{
//
// Call function to execute the instruction
//
(DecodeInstructionFunctionTable[DecodeInstructionTable[OperationCodeByte][InstructionSubIndex]])();
}
//
// If the trap flag was set then exit the emulator.
//
if (TrapFlagSet)
{
ErrorCode = x86BiosTrapFlagAsserted;
ExitFlag = TRUE;
}
}
}
static VOID x86FarCall(
USHORT pCS,
USHORT pIP
)
/*++
Routine Description:
This function makes a far call to the instruction at pCS:pIP. The
emulator will exit when the far call returns. To set up the exit
condition, a far call instruction is built at 0000:0501. CS and IP
are then initialized to 0000:0501, and the exit condition is intialized
to 0000:0506. When the emulator returns from the far call constructed at
0000:0501, it will attempt to execute the instruction at 0000:0506, but
the exit condition has been met, so the emulator exits.
Arguments:
pCS - Segment of the far call.
pIP - Offset of the far call.
Return Value:
None.
--*/
{
//
// Build the far call instruction.
//
PutAbsoluteMem(0x00501,0x9a);
PutAbsoluteMem(0x00502,pIP);
PutAbsoluteMem(0x00503,pIP >> 8);
PutAbsoluteMem(0x00504,pCS);
PutAbsoluteMem(0x00505,pCS >> 8);
//
// Initialize the exit condition.
//
ExitSegment = 0x0000;
ExitOffset = 0x0506;
//
// Initialize the instruction pointer.
//
CS = 0x0000;
CSCacheRegister = GetSegmentCacheRegister(CS);
IP = 0x0501;
//
// Start the emulator
//
Interpreter();
}
X86BIOS_STATUS X86BiosInitializeAdapter(
ULONG Address
)
/*++
Routine Description:
This function attempts to initialize the adapter whose BIOS starts at
Address. First, a BIOS signature is verified. If the byte stored at
Address is 0x55 and the byte stored at Address+1 is 0xAA, then a
correct BIOS signature is present. Then, the byte at Address+2 encodes
the length of the BIOS across which a check sum should be performed. If
this check sum is verified, then a far call is made the Address+3.
Arguments:
Address - 20 bit base address of the adapter BIOS to be initialize.
Return Value:
None.
--*/
{
ULONG i;
ErrorCode = x86BiosSuccess;
//
// Check for a valid adapter BIOS signature.
//
if (GetAbsoluteMem(Address)!=0x55 || GetAbsoluteMem(Address+1)!=0xAA)
{
ErrorCode = x86BiosNoVideoBios;
return(ErrorCode);
}
//
// Perform checksum using byte 2 as the length of bios to perform check sum across
// If not correct set ErrorCode to InvalidBiosChecksum.
//
if (ErrorCode==x86BiosSuccess)
{
//
// Not implemented yet.
//
}
if (ErrorCode==x86BiosSuccess)
{
//
// Make a far call to Address + 3.
//
Address+=3;
x86FarCall(Address >>4,Address&0x000f);
}
//
// If an error occurred, send some info out the debug port.
//
if (ErrorCode!=x86BiosSuccess)
{
KdPrint(("x86Int() : ErrorCode = %d\n",ErrorCode));
KdPrint((" ISA I/O Virtul Base = %08X\n",BiosIsaIoBaseAddress));
KdPrint((" ISA Memory Virtual Base = %08x\n",ISABaseAddress));
KdPrint((" Main Memory [0-0x800] = %08X\n",VDMBaseAddress));
KdPrint((" CS:IP = %04X:%04X\n ",CS,CurrentIP.X));
for(i=0;i<16;i++)
KdPrint(("%02X ",GetMemImmediate(CS,CurrentIP.X+i)));
KdPrint(("\n"));
}
return(ErrorCode);
}
X86BIOS_STATUS X86BiosExecuteInt(
USHORT Type,
PX86BIOS_CONTEXT Arguments
)
/*++
Routine Description:
This function executes an INT call. It assumes that the interrupt
vector table has already been initialized, and that the INT vector
for Type is valid. The values for the registers AX,BX,CX,DX,SI,DI, and
BP are passed in Arguments. These registers are initialized to
their new values, and an INT instruction is constructed at 0000:0506.
The exit condition is initialized to 0000:0508. After the INT call
completes, the new values of AX,BX,CX,DX,SI,DI,BP are placed back into
the Arguments data structure.
Arguments:
Type - 8 bit interrupt type.
Arguments - Data structure used to pass in and pass out the values
of the registers AX,BX,CX,DX,SI,DI, and BP.
Return Value:
Success if no error were encountered. Otherwise, an error code from
the emulator.
--*/
{
ULONG i;
ErrorCode = x86BiosSuccess;
//
// Initialize register values
//
EAX = Arguments->Eax;
EBX = Arguments->Ebx;
ECX = Arguments->Ecx;
EDX = Arguments->Edx;
ESI = Arguments->Esi;
EDI = Arguments->Edi;
EBP = Arguments->Ebp;
ES = 0;
DS = 0;
Flags.X = 0;
//
// Build INT Type instruction.
//
PutAbsoluteMem(0x00506,0xcd);
PutAbsoluteMem(0x00507,Type);
//
// Initialize exit condition.
//
ExitSegment = 0x0000;
ExitOffset = 0x0508;
//
// Initialize instruction pointer.
//
CS = 0x0000;
CSCacheRegister = GetSegmentCacheRegister(CS);
IP = 0x0506;
//
// Start the emulator.
//
Interpreter();
//
// Copy the new register values back into Arguments.
//
Arguments->Eax = EAX;
Arguments->Ebx = EBX;
Arguments->Ecx = ECX;
Arguments->Edx = EDX;
Arguments->Esi = ESI;
Arguments->Edi = EDI;
Arguments->Ebp = EBP;
//
// If an error occurred, send some info out the debug port.
//
if (ErrorCode!=x86BiosSuccess) {
DbgPrint(("x86Int() : ErrorCode = %d\n",ErrorCode));
DbgPrint((" ISA I/O Virtul Base = %08X\n",BiosIsaIoBaseAddress));
DbgPrint((" ISA Memory Virtual Base = %08x\n",ISABaseAddress));
DbgPrint((" Main Memory [0-0x800] = %08X\n",VDMBaseAddress));
DbgPrint((" CS:IP = %04X:%04X\n ",CS,CurrentIP.X));
for(i=0;i<16;i++)
DbgPrint(("%02X ",GetMemImmediate(CS,CurrentIP.X+i)));
DbgPrint(("\n"));
DbgBreakPoint();
}
return(ErrorCode);
}
VOID X86BiosInitialize(
ULONG IsaIoVirtualBase,
ULONG IsaMemoryVirtualBase
)
/*++
Routine Description:
This function initialize the state of the 80286 processor, and the
state of the available memory.
Arguments:
IsaIoVirtualBase - Noncached virtual address range that is 64KB long
and is mapped to the system's ISA I/O range.
IsaMemoryVirtualBase - Noncached virtual address ranges that is 1MB
long ans is mapped to the system's ISA memory
range.
Return Value:
Success if no error were encountered. Otherwise, an error code from
the emulator.
--*/
{
ULONG i;
//
// Initialize state of the 80286 processor.
//
SegmentOveridePrefix = FALSE;
RepeatPrefix = FALSE;
LockPrefix = FALSE;
IP = 0;
CS = 0;
CSCacheRegister = GetSegmentCacheRegister(CS);
DS = 0;
SS = 0;
SSCacheRegister = GetSegmentCacheRegister(SS);
ES = 0;
AX = 0;
BX = 0;
CX = 0;
DX = 0;
SP = 0;
BP = 0;
SI = 0;
DI = 0;
Flags.X = 0;
msw = 0;
gdtBase = 0;
gdtLimit = 0;
idtBase = 0;
idtLimit = 0;
//
// Initialize the variables used to perform I/O and memory operations.
//
BiosIsaIoBaseAddress = IsaIoVirtualBase;
ISABaseAddress = IsaMemoryVirtualBase;
VDMBaseAddress = (ULONG)(&(MemoryArray[0]));
//
// Intiialize all 256 INT vector to jump to 0000:0500
//
for(i=0;i<256;i++)
{
PutAbsoluteMem(i*4+0,0x00); // Fill in all INT vectors to jump to 0x00500
PutAbsoluteMem(i*4+1,0x05);
PutAbsoluteMem(i*4+2,0x00);
PutAbsoluteMem(i*4+3,0x00);
}
//
// Place an IRET instruction at 0000:0500.
// This way, if an INT call is made that does not exist, the emulator
// will just immediatly reach its exit condition and return.
//
PutAbsoluteMem(0x00500,0xcf);
//
// Intialize the spack pointer to the top of the available memory.
//
SS = 0x0000;
SP = 0x07fe;
}