You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
603 lines
10 KiB
603 lines
10 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
addops.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the code to emulate the add, sub, adc, sbb,
|
|
inc, dec, and neg opcodes.
|
|
|
|
Author:
|
|
|
|
David N. Cutler (davec) 2-Sep-1994
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "nthal.h"
|
|
#include "emulate.h"
|
|
|
|
//
|
|
// Define forward referenced prototypes.
|
|
//
|
|
|
|
VOID
|
|
XmAddOperands (
|
|
IN PRXM_CONTEXT P,
|
|
IN ULONG Carry
|
|
);
|
|
|
|
VOID
|
|
XmSubOperands (
|
|
IN PRXM_CONTEXT P,
|
|
IN ULONG Borrow
|
|
);
|
|
|
|
VOID
|
|
XmAddOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates an add opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Add operands and store result.
|
|
//
|
|
|
|
XmAddOperands(P, 0);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmAdcOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates an add with carry opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Add operands with carry and store result.
|
|
//
|
|
|
|
XmAddOperands(P, P->Eflags.EFLAG_CF);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmSbbOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates a subtract with borrow opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG Source;
|
|
|
|
//
|
|
// Subtract operands with borrow and store result.
|
|
//
|
|
|
|
XmSubOperands(P, P->Eflags.EFLAG_CF);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmSubOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates a subtract opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Subtract operands and store result.
|
|
//
|
|
|
|
XmSubOperands(P, 0);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmCmpOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates a cmp opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Subtract operands to perform comparison operation.
|
|
//
|
|
|
|
XmSubOperands(P, 0);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmCmpxchgOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates a cmpxchg opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG Accumulator;
|
|
ULONG Destination;
|
|
|
|
//
|
|
// Compare the destination with the accumulator. If the destination
|
|
// operand is equal to the accumulator, then set ZF and store the
|
|
// source operand value in the destination opperand. Otherwise, clear
|
|
// ZF and store the destination operand in the accumlator.
|
|
//
|
|
|
|
Destination = P->DstValue.Long;
|
|
if (P->DataType == BYTE_DATA) {
|
|
Accumulator = P->Gpr[AL].Xl;
|
|
|
|
} else if (P->DataType == LONG_DATA) {
|
|
Accumulator = P->Gpr[EAX].Exx;
|
|
|
|
} else {
|
|
Accumulator = P->Gpr[AX].Xx;
|
|
}
|
|
|
|
if (Destination == Accumulator) {
|
|
P->Eflags.EFLAG_ZF = 1;
|
|
XmStoreResult(P, P->SrcValue.Long);
|
|
|
|
} else {
|
|
P->Eflags.EFLAG_ZF = 0;
|
|
P->DstLong = (ULONG UNALIGNED *)(&P->Gpr[EAX].Exx);
|
|
XmStoreResult(P, P->DstValue.Long);
|
|
}
|
|
|
|
//
|
|
// Subtract operands to perform comparison operation.
|
|
//
|
|
|
|
P->SrcValue.Long = P->DstValue.Long;
|
|
P->DstValue.Long = Accumulator;
|
|
XmSubOperands(P, 0);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmDecOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates a decrement opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Subtract operands and store result.
|
|
//
|
|
//
|
|
|
|
P->SrcValue.Long = 1;
|
|
XmSubOperands(P, 0);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmIncOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates an increment opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Add operands and store result.
|
|
//
|
|
|
|
P->SrcValue.Long = 1;
|
|
XmAddOperands(P, 0);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmNegOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates a neg opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
|
|
//
|
|
// Subtract operand from zero and store result.
|
|
//
|
|
|
|
P->SrcValue.Long = P->DstValue.Long;
|
|
P->DstValue.Long = 0;
|
|
XmSubOperands(P, 0);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmXaddOp (
|
|
IN PRXM_CONTEXT P
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function emulates an xadd opcode.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG Destination;
|
|
|
|
//
|
|
// Exchange add operands and store result.
|
|
//
|
|
|
|
Destination = P->DstValue.Long;
|
|
XmAddOperands(P, 0);
|
|
P->DstLong = P->SrcLong;
|
|
XmStoreResult(P, Destination);
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmAddOperands (
|
|
IN PRXM_CONTEXT P,
|
|
IN ULONG Carry
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function adds two operands and computes the resulting condition
|
|
codes.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Carry - Supplies the carry value.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG CarryFlag;
|
|
ULONG Shift;
|
|
union {
|
|
UCHAR ResultByte;
|
|
ULONG ResultLong;
|
|
USHORT ResultWord;
|
|
} u;
|
|
|
|
u.ResultLong = 0;
|
|
if (P->DataType == BYTE_DATA) {
|
|
u.ResultByte = P->SrcValue.Byte + (UCHAR)Carry;
|
|
CarryFlag = u.ResultByte < (UCHAR)Carry;
|
|
u.ResultByte += P->DstValue.Byte;
|
|
CarryFlag |= (u.ResultByte < P->DstValue.Byte);
|
|
Shift = 7;
|
|
|
|
} else if (P->DataType == LONG_DATA) {
|
|
u.ResultLong = P->SrcValue.Long + Carry;
|
|
CarryFlag = (u.ResultLong < Carry);
|
|
u.ResultLong += P->DstValue.Long;
|
|
CarryFlag |= (u.ResultLong < P->DstValue.Long);
|
|
Shift = 31;
|
|
|
|
} else {
|
|
u.ResultWord = P->SrcValue.Word + (USHORT)Carry;
|
|
CarryFlag = (u.ResultWord < (USHORT)Carry);
|
|
u.ResultWord += P->DstValue.Word;
|
|
CarryFlag |= (u.ResultWord < P->DstValue.Word);
|
|
Shift = 15;
|
|
}
|
|
|
|
//
|
|
// Store the result.
|
|
//
|
|
|
|
XmStoreResult(P, u.ResultLong);
|
|
|
|
//
|
|
// If the function is not an increment, then store the carry flag.
|
|
//
|
|
|
|
if (P->FunctionIndex != X86_INC_OP) {
|
|
P->Eflags.EFLAG_CF = CarryFlag;
|
|
}
|
|
|
|
//
|
|
// Compute and store the parity and auxiliary carry flags.
|
|
//
|
|
|
|
P->Eflags.EFLAG_PF = XmComputeParity(u.ResultLong);
|
|
P->Eflags.EFLAG_AF = ((P->DstValue.Byte & 0xf) +
|
|
(P->SrcValue.Long & 0xf) + Carry) >> 4;
|
|
|
|
//
|
|
// Compute and store the zero and sign flags.
|
|
//
|
|
|
|
P->Eflags.EFLAG_ZF = (u.ResultLong == 0);
|
|
P->Eflags.EFLAG_SF = u.ResultLong >> Shift;
|
|
|
|
//
|
|
// The overflow flag is computed as the carry into the sign bit
|
|
// compared with the carry out of the sign bit.
|
|
//
|
|
|
|
P->Eflags.EFLAG_OF = (((P->SrcValue.Long ^ P->DstValue.Long) ^
|
|
u.ResultLong) >> Shift) ^ CarryFlag;
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
XmSubOperands (
|
|
IN PRXM_CONTEXT P,
|
|
IN ULONG Borrow
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function adds to operands and computes the resulting condition
|
|
codes.
|
|
|
|
Arguments:
|
|
|
|
P - Supplies a pointer to the emulation context structure.
|
|
|
|
Borrow - Supplies the boorow value.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG CarryFlag;
|
|
ULONG Shift;
|
|
union {
|
|
UCHAR ResultByte;
|
|
ULONG ResultLong;
|
|
USHORT ResultWord;
|
|
} u;
|
|
|
|
u.ResultLong = 0;
|
|
if (P->DataType == BYTE_DATA) {
|
|
CarryFlag = (P->DstValue.Byte < (UCHAR)Borrow);
|
|
u.ResultByte = P->DstValue.Byte - (UCHAR)Borrow;
|
|
CarryFlag |= (u.ResultByte < P->SrcValue.Byte);
|
|
u.ResultByte -= P->SrcValue.Byte;
|
|
Shift = 7;
|
|
|
|
} else if (P->DataType == LONG_DATA) {
|
|
CarryFlag = (P->DstValue.Long < Borrow);
|
|
u.ResultLong = P->DstValue.Long - Borrow;
|
|
CarryFlag |= (u.ResultLong < P->SrcValue.Long);
|
|
u.ResultLong -= P->SrcValue.Long;
|
|
Shift = 31;
|
|
|
|
} else {
|
|
CarryFlag = (P->DstValue.Word < (USHORT)Borrow);
|
|
u.ResultWord = P->DstValue.Word - (USHORT)Borrow;
|
|
CarryFlag |= (u.ResultWord < P->SrcValue.Word);
|
|
u.ResultWord -= P->SrcValue.Word;
|
|
Shift = 15;
|
|
}
|
|
|
|
//
|
|
// If the fucntion is not a compare or a compare and swap, then store
|
|
// result.
|
|
//
|
|
|
|
if ((P->FunctionIndex != X86_CMP_OP) && (P->FunctionIndex != X86_CMPXCHG_OP)) {
|
|
XmStoreResult(P, u.ResultLong);
|
|
}
|
|
|
|
//
|
|
// If the function is not a decrement, then store the carry flag.
|
|
//
|
|
|
|
if (P->FunctionIndex != X86_DEC_OP) {
|
|
P->Eflags.EFLAG_CF = CarryFlag;
|
|
}
|
|
|
|
//
|
|
// Compute and store the parity and auxiliary carry flags.
|
|
//
|
|
|
|
P->Eflags.EFLAG_PF = XmComputeParity(u.ResultLong);
|
|
P->Eflags.EFLAG_AF = ((P->DstValue.Byte & 0xf) -
|
|
(P->SrcValue.Byte & 0xf) - Borrow) >> 4;
|
|
|
|
//
|
|
// If the function is not a compare and swap, then compute the zero flag.
|
|
//
|
|
|
|
if (P->FunctionIndex != X86_CMPXCHG_OP) {
|
|
P->Eflags.EFLAG_ZF = (u.ResultLong == 0);
|
|
}
|
|
|
|
//
|
|
// Compute and store the sign flag.
|
|
//
|
|
|
|
P->Eflags.EFLAG_SF = u.ResultLong >> Shift;
|
|
|
|
//
|
|
// The overflow flag is computed as the borrow from the sign bit
|
|
// compared with the borrow into the sign bit.
|
|
//
|
|
|
|
P->Eflags.EFLAG_OF = (((P->SrcValue.Long ^ P->DstValue.Long) ^ u.ResultLong) >> Shift) ^ CarryFlag;
|
|
return;
|
|
}
|